# Dynamic Argument Storage in fmtlib: A Complete Guide to `fmt::dynamic_format_arg_store`

> Discover fmtlib's dynamic argument storage with fmt::dynamic_format_arg_store. Build formatting argument lists at runtime, even with named arguments. Learn more.

- Repository: [Hello World Foundation/fmt](https://github.com/fmtlib/fmt)
- Tags: deep-dive
- Published: 2026-09-10

---

**The fmt library supports fully-featured dynamic argument storage through the `fmt::dynamic_format_arg_store` class template, enabling runtime construction of formatting argument lists with optional named arguments.**

The {fmt} library (fmtlib/fmt) is widely recognized for its fast, type-safe formatting capabilities. While compile-time format strings offer optimal performance, many applications require the flexibility to build argument lists dynamically at runtime. This article explores how `fmt::dynamic_format_arg_store` provides this capability according to the fmtlib source code.

## Understanding `dynamic_format_arg_store`

The `dynamic_format_arg_store` class template, defined in [`include/fmt/args.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/args.h), serves as a container for building argument lists programmatically. Unlike static argument lists known at compile time, this store allows you to push arguments conditionally or iteratively during program execution.

The implementation uses a dual-storage architecture:

- **`data_` vector**: A contiguous storage block at lines 98-100 holding `basic_format_arg<Context>` entries. This layout supports pointer arithmetic required by the formatting engine.
- **`dynamic_args_` list**: Secondary storage at lines 102-105 for values requiring dynamic allocation, such as custom types or copied strings. Elements in `data_` maintain references into this list, which must never relocate its elements.

## Pushing Arguments at Runtime

The store provides multiple `push_back` overloads to handle different argument types safely.

### Basic Value Storage

Values are stored using `push_back()` at lines 53-58 and 73-78. The library automatically determines whether a value can be stored by reference or requires copying:

```cpp
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
store.push_back("hello");
store.push_back(3.14);
std::string s = fmt::vformat("{} {} {}", store);  // "42 hello 3.14"

```

### Reference Storage Without Copying

To avoid copying built-in types or string views, wrap arguments in `std::reference_wrapper`:

```cpp
int value = 10;
store.push_back(std::cref(value));  // stores reference only
value = 20;
std::string s2 = fmt::vformat("{}", store);  // "20"

```

This capability is essential when working with large objects or when the underlying data must outlive the formatting operation.

## Working with Named Arguments

Dynamic storage fully supports named arguments through `fmt::arg()`, implemented in the same header:

```cpp
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(fmt::arg("name", "Alice"));
store.push_back(fmt::arg("age", 30));
std::string s3 = fmt::vformat("{name} is {age} years old", store);
// Result: "Alice is 30 years old"

```

The store handles the mapping between named argument identifiers and their values internally, making named formatting accessible at runtime.

## Memory Management and Capacity Control

The class provides explicit control over memory allocation through utility methods defined around lines 96-104:

- **`clear()`**: Empties the store for reuse
- **`size()`**: Returns the current argument count
- **`reserve(size_type n, size_type num_named_args = 0)`**: Pre-allocates capacity for `n` total arguments with `num_named_args` named slots

```cpp
store.reserve(10, 2);  // Reserve space for 10 total args, 2 named args

```

This reservation strategy minimizes reallocations when the argument count is known in advance.

## Integration with the Formatting Engine

At lines 31-36, the store implements implicit conversion to `basic_format_args<Context>`. This design allows seamless integration with type-erased formatting functions:

```cpp
// Implicit conversion works with any function expecting basic_format_args
fmt::vformat_to(std::back_inserter(buffer), format_string, store);

```

The conversion efficiency is optimized because `basic_format_args` can directly reference the contiguous `data_` array without additional copying.

## Summary

- **`dynamic_format_arg_store`** in [`include/fmt/args.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/args.h) provides comprehensive runtime argument collection for the fmt library.
- **Dual storage architecture** separates contiguous argument metadata (`data_`) from dynamically allocated values (`dynamic_args_`).
- **Flexible insertion methods** support both copying and reference storage via `push_back()` overloads.
- **Named argument support** integrates fully with `fmt::arg()` and positional formatting.
- **Implicit conversion** to `basic_format_args` enables direct use with `fmt::vformat` and related APIs.
- **Memory management utilities** include `reserve()`, `clear()`, and `size()` for production-grade resource control.

## Frequently Asked Questions

### What is the purpose of `dynamic_format_arg_store` in fmt?

`dynamic_format_arg_store` enables runtime construction of formatting argument lists when the number, types, or values of arguments are not known at compile time. It is essential for applications that build format strings dynamically, such as logging frameworks, localization systems, or configuration-driven output generators.

### How does fmt handle memory for dynamic arguments?

The implementation uses two distinct storage mechanisms. The `data_` member stores `basic_format_arg` objects contiguously for fast indexed access, while `dynamic_args_` holds values requiring heap allocation. This separation ensures the formatting engine can use pointer arithmetic on `data_` while safely managing lifetimes for complex types.

### Can I use named arguments with dynamic storage?

Yes. The `push_back()` overload accepting `named_arg<T, char_type>` at lines 73-78 allows you to add named arguments using `fmt::arg("key", value)`. These named arguments work identically to compile-time named arguments when passed to `fmt::vformat`.

### Is dynamic argument storage slower than compile-time formatting?

Dynamic storage incurs minor overhead compared to compile-time format strings because it requires runtime type erasure and virtual dispatch through `basic_format_args`. However, the implementation minimizes this cost through contiguous storage layout and efficient reference handling, maintaining performance suitable for most I/O-bound applications.