pmr · part 01

std::pmr is one abstract class with three functions

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

Most allocator tutorials open with a wall of template parameters. std::pmr does not. The whole polymorphic memory resource framework, the arenas, the pools, every pmr::vector and pmr::string, sits on one abstract class with three functions you can override in an afternoon.

That class is std::pmr::memory_resource. This is the entire interface you implement:

  • do_allocate(bytes, align) returns a block of that size.
  • do_deallocate(ptr, bytes, align) reclaims it.
  • do_is_equal(other) answers whether memory from other can be freed here.

Everything else in <memory_resource> is built on that seam.

A resource in a dozen lines

Here is a resource that does nothing but forward to another one and print what it was asked for. I gave it an upstream so it can sit in front of a real allocator.

The first vector allocates straight through the logger. libstdc++ grows a vector by doubling, so eight push_backs ask for 4, then 8, 16, and 32 bytes: four separate requests, each one printed.

The second vector is where composition shows up. Same logging resource, but now a monotonic_buffer_resource sits in front of it, backed by 512 bytes on the stack. The vector takes its memory from the arena, and the arena carves it out of that one buffer. The upstream logger is never called. Four heap-bound requests became zero.

Why resources compose

monotonic_buffer_resource is not special-cased inside the vector. It is another memory_resource, three functions like any other, and the vector cannot tell the difference. Because the allocator is chosen at runtime behind one virtual call, resources stack: a pool in front of an arena in front of the heap is three objects wired by pointer, not three template instantiations.

The standard ships a handful of them. monotonic_buffer_resource bump-allocates and frees nothing until it is reset. synchronized_pool_resource and its unsynchronized twin manage fixed-size block pools. new_delete_resource is the default, backed by operator new. And null_memory_resource throws on every request, which is how you prove a hot path never touches the heap: chain it as the upstream of a monotonic buffer, and any spill past the buffer throws instead of allocating.

pmr has been in the standard since C++17. The model came from Bloomberg’s allocator work and was standardized by Pablo Halpern. Three functions, and the containers you already use will allocate from anything you can describe.


Sources: cppreference: std::pmr::memory_resource · cppreference: monotonic_buffer_resource · Pablo Halpern, N3916 (the pmr proposal).