pmr · part 07

Making your own type allocator-aware needs a second constructor

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

Every example so far used a standard container. The moment you put a pmr::string or pmr::vector inside a struct of your own, you inherit a new obligation: your type has to pass the allocator down to its members, or they quietly allocate from the default resource while the object around them lives in an arena.

Making a type allocator-aware has three parts. It declares using allocator_type = std::pmr::polymorphic_allocator<...>. It accepts an optional allocator argument in its constructors. And it forwards that allocator to each member that can use one.

Record holds a pmr::string. Its normal constructor takes a trailing allocator argument and passes it to the string, so the name lands in the arena. It also has a second constructor, the allocator-extended copy: the same value as an existing Record, but built with a caller-supplied allocator. That is the “secret twin” every constructor grows once a type is allocator-aware, and it is what lets a pmr::vector<Record> place each element’s string in its own arena. The demo confirms both the standalone Record and the one inside the vector use the arena.

Uses-allocator construction, briefly

When pmr::vector<Record> builds an element, it does not just call Record(args...). It checks whether Record advertises an allocator_type, and if so it appends its own allocator to the constructor call. This is uses-allocator construction, and it is why a single arena passed to the outer vector reaches all the way down to the innermost string. Miss any link in that chain, a constructor that forgets to take or forward the allocator, and the memory silently escapes to the default heap at that point.

This is the real cost of adopting pmr, and it is a design cost, not a runtime one. A type with one string member grows a second constructor and an allocator_type. In exchange, your whole object graph can be handed a single arena and honor it. The standard library types already pay this tax for you; your own types have to opt in.


Sources: cppreference: uses-allocator construction · Pablo Halpern, P3002: policies for using allocators in new library classes.