How absl::Cord Compares to std::string for Large String Operations
absl::Cord uses a chunked tree structure to provide O(1) amortized append, prepend, and copy operations, making it superior to std::string for large or frequently mutated data, while trading off O(1) random access speed.
When working with large strings in the abseil/abseil-cpp library, choosing between absl::Cord and std::string directly impacts your application's memory efficiency and throughput. Unlike std::string, which stores data in a single contiguous buffer, absl::Cord manages a tree of chunks that enables zero-copy sharing and efficient end modifications without reallocating existing data.
Performance Characteristics of absl::Cord vs std::string
Appending and Prepending Operations
absl::Cord provides O(1) amortized complexity for appending and prepending operations, while std::string requires O(N) time when reallocation is necessary. According to the class documentation in absl/strings/cord.h (lines 31-41), Cord is specifically optimized for efficient insertions at the beginning and end of the string.
The implementation in absl/strings/cord.cc reveals how this optimization works. The AppendPrecise method (lines 9-18) checks for an existing inline buffer with spare capacity and writes directly into it, or appends a new flat chunk without touching the rest of the data. Similarly, PrependPrecise (lines 21-32) mirrors this logic for front insertions, avoiding the buffer shifts that plague std::string.
Memory Sharing and Copy-on-Write
Copying a Cord is an O(1) operation that merely increments a reference count, as documented in absl/strings/cord.h (lines 40-44). This copy-on-write mechanism allows multiple Cord objects to share the same underlying chunk tree, making it ideal for scenarios where large immutable data must be passed between multiple owners.
In contrast, std::string always allocates a new buffer and copies the data, resulting in O(N) complexity. The Subcord method further leverages this architecture by creating a view over existing chunks without copying bytes, something impossible with contiguous string storage.
External Memory References
absl::Cord can attach existing memory without copying through MakeCordFromExternal, while std::string must always copy data into its own buffer. This capability allows you to wrap externally allocated buffers—such as memory-mapped files or network buffers—into a Cord interface with zero overhead. The source code notes this as one of the three primary advantages of Cord over standard strings.
Random Access Trade-offs
The chunked architecture comes with a cost: random access in absl::Cord requires O(log N) time to traverse the B-tree structure, whereas std::string provides O(1) access via pointer arithmetic. This trade-off makes std::string the better choice for algorithms that frequently index into arbitrary positions, while Cord excels in streaming and append-heavy workloads.
Implementation Details in the Abseil Source Code
The performance characteristics of absl::Cord stem from its internal representation across several key files:
absl/strings/internal/cord_rep_btree.h: Implements the B-tree representation that enables O(log N) navigation while maintaining O(1) end operations.absl/strings/internal/cord_rep_flat.h: Defines flat chunk objects used for large appends without requiring a full tree rebalancing.absl/strings/internal/cord_internal.h: Provides low-level helpers likeRemoveCrcNodeandSkipCrcNodethat maintain tree efficiency during mutations.absl/strings/cord.h: Contains the public API and theCopyCordToStringutility (lines 19-27), which efficiently converts Cord tostd::stringby reusing the destination's capacity when possible.
When to Use absl::Cord Instead of std::string
Use absl::Cord when your workload matches these criteria:
- Large strings with frequent append/prepend operations: Avoid the O(N) reallocations inherent in
std::stringgrowth. - Data sharing across multiple components: Leverage cheap copy-on-write semantics to avoid duplicating large buffers.
- External memory management: Wrap existing buffers without copying via
MakeCordFromExternal. - Substring operations: Create lightweight views with
Subcordrather than copying data segments.
Practical Code Examples
#include "absl/strings/cord.h"
#include <string>
#include <iostream>
int main() {
// 1. Build a huge cord by repeatedly appending without reallocations.
absl::Cord big;
for (int i = 0; i < 1'000'000; ++i) {
big.Append("x"); // O(1) per iteration
}
std::cout << "size: " << big.size() << '\n';
// 2. Zero-copy external memory.
const char* data = "already-allocated payload";
absl::Cord external = absl::MakeCordFromExternal(
absl::string_view(data, strlen(data)),
[](absl::string_view) { /* no-op releaser */ });
// No copy of `data` happened.
// 3. Cheap copy / sharing.
absl::Cord copy = big; // Only ref-count increments (O(1))
std::cout << "copy size: " << copy.size() << '\n';
// 4. Fast sub-cord (view) without copying.
absl::Cord view = big.Subcord(100, 200); // O(1) view over the same chunks
std::cout << "view size: " << view.size() << '\n';
// 5. Convert to std::string efficiently if we already have capacity.
std::string dst;
dst.reserve(big.size()); // allocate once
absl::CopyCordToString(big, &dst); // reuses capacity, no extra allocs
std::cout << "dst length: " << dst.size() << '\n';
}
This example demonstrates how Append operations manipulate the underlying chunk tree rather than moving large blocks of memory, and how CopyCordToString optimizes the conversion path when the destination std::string has pre-allocated capacity.
Summary
absl::Cordstores data in a chunked tree structure, whilestd::stringuses a contiguous buffer.- Append and prepend operations are O(1) amortized in Cord versus O(N) in
std::string. - Cord provides O(1) copy-on-write semantics through reference counting, while
std::stringalways copies data. - Random access is O(log N) in Cord compared to O(1) in
std::string. - Cord can reference external memory without copying via
MakeCordFromExternal.
Frequently Asked Questions
Is absl::Cord always faster than std::string?
No. absl::Cord is optimized for large, mutable, and shared strings, but std::string provides faster O(1) random access and lower overhead for small strings. For short, fixed-size data or algorithms requiring frequent character indexing, std::string remains the better choice.
How does absl::Cord handle memory internally?
According to the source in absl/strings/internal/cord_rep_btree.h, Cord uses a B-tree of chunks to store data. Small strings may live in an inline buffer within the Cord object itself, while larger data is stored in reference-counted flat chunks managed by the tree structure in cord_rep_flat.h.
Can I convert absl::Cord to std::string efficiently?
Yes. The CopyCordToString function in absl/strings/cord.h (lines 19-27) optimizes the conversion by reusing the destination string's existing capacity. If you call dst.reserve(cord.size()) before conversion, the operation avoids additional allocations and copies the data directly into the std::string buffer.
When should I avoid using absl::Cord?
Avoid absl::Cord when you need frequent random access to individual characters, when working with small strings where the overhead of reference counting outweighs the benefits, or when interfacing with APIs that strictly require null-terminated C strings without the ability to convert. For these scenarios, std::string or std::string_view provide better performance characteristics.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →