pmr · part 02

A pmr::vector on a stack buffer never calls new

· english· audience: working-cpp· AI-generated, reviewed by Filip Sajdak

The expensive part of std::vector is rarely the arithmetic. It is the call into the global allocator every time the vector grows, and on a hot path (an order book update, one frame of a game loop) that call is where the latency spikes hide. std::pmr lets you pay for the memory once, up front, then run without touching the allocator at all.

Here is the claim, made testable. I overrode the global operator new to count every heap allocation, then filled a pmr::vector<int> with ten thousand values. The vector draws from a monotonic_buffer_resource backed by 256 KB on the stack. Its upstream is null_memory_resource, which throws on any request, so if the vector ever spilled past the buffer the program would abort instead of quietly reaching the heap.

Zero. Ten thousand push_backs, several reallocations as the vector doubled, and the global allocator was never called. Every byte came from the stack buffer.

The buffer is the budget

The monotonic_buffer_resource from episode 1 bump-allocates: each request advances a pointer into the buffer, and nothing is freed until the whole resource is reset or destroyed. That is exactly what a per-event or per-frame arena wants. Do the work, then release() the arena and the next event starts from the top of the same buffer. No per-object bookkeeping, no free list, no fragmentation within the round.

null_memory_resource as the upstream is the part worth copying. It turns “should not allocate” into “cannot allocate”: a spill throws at the call site instead of silently succeeding on the heap and costing you a latency spike you will chase later. If you size the buffer wrong, you find out in testing, loudly.

The container never changed. A pmr::vector<int> is an ordinary vector; only the resource behind it moved from the heap to the stack.


Sources: cppreference: monotonic_buffer_resource · cppreference: null_memory_resource.