Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

std::pmr::polymorphic_allocator keeps the allocator type stable while letting you choose the allocation strategy at runtime through a std::pmr::memory_resource. Use a monotonic resource when allocations share a bulk lifetime, a pool when blocks are repeatedly allocated and freed, and a custom or forwarding resource when you need diagnostics or a particular allocation source. The right choice depends on lifetime and thread access—not an assumption that PMR is automatically faster.

How C++17 polymorphic allocators work

The C++17 <memory_resource> library separates the allocator passed to an allocator-aware container from the strategy that supplies its storage. A std::pmr::polymorphic_allocator<T> carries a pointer to a memory_resource; the resource is selected at runtime, while the allocator type remains the same. This can let an API vary its allocation policy without encoding a different allocator type into each container type. See the polymorphic allocator reference and the C++17 memory_resource header reference.

For example, std::pmr::vector<T> is a vector using a polymorphic allocator. Constructing it with a resource selects where its storage requests go. The resource does not construct or destroy objects for the container: it provides storage, while the container and normal C++ object-lifetime rules govern construction and destruction.

Nested allocations require allocator-aware types

Allocator-aware construction can propagate the selected resource into nested PMR objects. For example, a std::pmr::vector<std::pmr::string> can pass its resource to the strings it constructs, so their character storage can use that resource too. By contrast, putting an ordinary std::string inside a PMR vector does not convert the string into a PMR string; its own allocations follow its ordinary allocator behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a custom type that owns dynamically allocating members, use allocator-aware construction and members that can accept the intended allocator or resource. Confirm that the actual construction path propagates the allocator; merely storing the custom type in a PMR container does not make every allocation it performs use the container’s resource.

Choose a resource by lifetime and access pattern

Need Resource How it behaves and what to watch
Many allocations are used during one phase and discarded together std::pmr::monotonic_buffer_resource Individual deallocation has no effect; consumed storage accumulates until release() or destruction. It can start with a caller-provided buffer and request more storage from an upstream resource.
Repeated allocation and deallocation of recurring block sizes, with one thread accessing the resource at a time std::pmr::unsynchronized_pool_resource Maintains pools of uniform blocks and avoids synchronization; it must not be accessed concurrently from multiple threads.
A similar pool pattern, with resource calls that may overlap across threads std::pmr::synchronized_pool_resource Supports concurrent access without external synchronization. Its synchronization does not make concurrent access to the containers or objects using it safe.
Custom allocation source, accounting, or diagnostics A derived memory_resource or forwarding wrapper Centralizes allocation requests as byte counts and alignments, but the implementation must preserve allocation, deallocation, equality, and lifetime requirements.

Monotonic resources fit phase-oriented lifetimes, not containers expected to return each erased element’s storage. The committee proposal N3816 describes the behavior directly: “A call to deallocate has no effect, thus the amount of memory consumed increases monotonically until the resource is destroyed.” The same proposal describes the resource’s buffer and upstream-allocation model: N3816: More Improvements to the C++14 Library.

How pool resources use storage

Pool resources serve requests from size-specific pools of uniform blocks. When a pool needs storage, it can acquire another chunk from its upstream resource; sufficiently large requests may go directly upstream rather than through a pool. Pool resources manage their acquired memory and release it when destroyed, even if clients have not individually deallocated every block.

Pool options, size classes, and exact behavior are partly implementation-dependent. Do not rely on a universal bucket table, growth factor, memory footprint, or speed advantage. Measure with the target standard library and workload if those details matter.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose synchronization for resource access, not as a container lock

Use synchronized_pool_resource if calls into the resource itself can happen concurrently. Use unsynchronized_pool_resource only when access is limited to one thread at a time. Synchronization inside a resource does not protect unrelated object or container operations; those still need their own concurrency design.

Pass a PMR resource into a custom type

A custom type should make its allocation policy explicit. If it owns dynamic storage, use allocator-aware construction as required by the library and choose allocator-aware member types, such as std::pmr::string, where the resource should apply. A resource passed to a PMR container will reach nested objects only when their construction supports that propagation.

Keep the resource alive for as long as any allocator-aware object may use it. For resource stacks, the upstream resource must outlive the resource that depends on it. With a monotonic resource, destroy objects using its storage before calling release(); freeing storage does not itself run their destructors. Pool storage being reclaimed when a pool is destroyed likewise does not remove the need to end client object lifetimes correctly.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Build a forwarding debug resource

std::pmr::memory_resource is an abstract interface. A derived implementation supplies three hooks: do_allocate(bytes, alignment), do_deallocate(pointer, bytes, alignment), and do_is_equal(other). The public allocation, deallocation, and equality operations dispatch through these hooks.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value

A diagnostic wrapper can forward requests to an upstream resource while recording metadata keyed by returned pointer. On deallocation it can check that the pointer is known and that the supplied byte count and alignment match the recorded request, then forward the deallocation. It can also track live bytes, allocation counts, or high-water marks. A custom resource could add guard regions, but that is an implementation choice—not a diagnostic feature guaranteed by the standard library.

Checks a resource implementation must satisfy

  • Return storage meeting both the requested size and alignment, and deallocate it through a compatible upstream resource.
  • Validate deallocations against recorded requests if the wrapper is intended to detect mismatched sizes, alignments, invalid pointers, or double frees. Do not forward a bad deallocation as if it were valid.
  • Make equality truthful: resources compare equal only when memory allocated through one can safely be deallocated through the other under the resource contract. For a stateful wrapper, identity equality is a conservative choice.
  • Ensure the upstream resource outlives the wrapper and that the wrapper outlives every object or allocator that may still call it.
  • Keep allocation bookkeeping internally safe if the wrapper itself is used concurrently; a synchronized upstream resource alone does not automatically protect the wrapper’s metadata.

These checks are especially useful in tests or when validating a custom allocation strategy. Instrumentation changes the allocation path and may affect behavior or performance, so treat measurements made with a debug wrapper accordingly.

Use the default resource deliberately

The memory-resource library provides default, new/delete, and null resources, as well as functions to get or change the process-wide default PMR resource. Changing that default affects PMR construction paths that consult it; it does not retroactively replace the resource held by already-constructed objects. Explicitly injecting a resource into a component is often easier to reason about in libraries and tests because the dependency is visible at the construction boundary.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.