memory_buffer and buffered output
fmt::memory_buffer is the container fmt itself uses internally to build formatted output — a small
inline buffer that lives on the stack and only reaches for the heap once the output outgrows it.
What it is
fmt::memory_buffer is basic_memory_buffer<char, 500>: 500 bytes of inline storage, growing onto
the heap for anything larger, exactly like a small-string-optimized string but without std::string's
null-termination guarantee.
fmt::memory_buffer buf;
fmt::format_to(std::back_inserter(buf), "{}: {}", key, value);
send(fd, buf.data(), buf.size());
Not null-terminated
write(fd, buf.data(), buf.size()); // correct — explicit length
puts(buf.data()); // wrong — reads past the end looking for '\0'
std::string s = fmt::to_string(buf); // correct — produces a proper null-terminated std::string
Choosing the inline size
fmt::basic_memory_buffer<char, N> lets you pick the inline capacity for a known-small message,
trading stack space for fewer heap allocations.
| Inline size | Stack cost | Allocates when |
|---|---|---|
| Default (500) | 500 bytes | Output exceeds 500 bytes |
128 (a typical log line) | 128 bytes | Output exceeds 128 bytes |
16 (a short status code) | 16 bytes | Output exceeds 16 bytes |
Size it to comfortably cover your typical output, not your worst case — an occasional heap allocation for a long outlier is cheaper than reserving kilobytes of stack for every call.
Reuse across calls
Calling buf.clear() between iterations of a loop reuses the same allocation (if the buffer already
grew onto the heap) instead of allocating fresh every time.
fmt::memory_buffer buf;
for (const auto& entry : entries) {
buf.clear();
fmt::format_to(std::back_inserter(buf), "{}: {}\n", entry.key, entry.value);
write_out(buf.data(), buf.size());
}
Handing it to an API
Depending on what the consumer expects: fmt::to_string(buf) for a std::string,
std::string_view(buf.data(), buf.size()) for a non-owning view, or write(fd, buf.data(), buf.size()) for a raw byte-oriented API.
When not to bother
The allocation fmt::format performs is a rounding error next to the cost of handling an HTTP
request. memory_buffer's value shows up when you're formatting thousands or millions of times per
second — see
Performance characteristics
for where allocation actually costs you and where it doesn't.
See also
- Output iterators and format_to — the general mechanism
memory_bufferplugs into. - Performance characteristics — when this optimization is and isn't worth reaching for.
- The format function family — the full set of entry points
memory_buffercomplements. - fmt overview — the full doc set.