# How absl::Cord Compares to std::string for Large String Operations

> Discover when to use absl Cord over std string for large string operations. Cord offers efficient appending and prepending with its chunked tree structure.

- Repository: [Abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)
- Tags: deep-dive
- Published: 2026-07-14

---

**`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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/absl/strings/internal/cord_internal.h)**: Provides low-level helpers like `RemoveCrcNode` and `SkipCrcNode` that maintain tree efficiency during mutations.
- **[`absl/strings/cord.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/strings/cord.h)**: Contains the public API and the `CopyCordToString` utility (lines 19-27), which efficiently converts Cord to `std::string` by 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::string` growth.
- **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 `Subcord` rather than copying data segments.

## Practical Code Examples

```cpp
#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::Cord`** stores data in a chunked tree structure, while **`std::string`** uses 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::string` always 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`](https://github.com/abseil/abseil-cpp/blob/main/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`](https://github.com/abseil/abseil-cpp/blob/main/cord_rep_flat.h).

### Can I convert absl::Cord to std::string efficiently?

Yes. The `CopyCordToString` function in [`absl/strings/cord.h`](https://github.com/abseil/abseil-cpp/blob/main/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.