the Allocator concept and std::pmr
By default, a std::vector or std::map asks the global heap (operator new, ultimately malloc()) every time it needs memory. For most code that is fine, but in systems work you sometimes need containers to draw memory from somewhere specific instead — a pre-reserved arena, a fixed buffer on the stack, a pool sized for one request — to control fragmentation, latency, or locality. C++ lets you do this by supplying a custom allocator that the container uses instead of the global heap.
An allocator is an object that knows how to hand out and reclaim raw memory of a given type; the standard library defines the Allocator concept (informally) as the set of operations a container expects — chiefly allocate(n) to obtain storage for n objects and deallocate(p, n) to give it back, plus type information. The classic template-parameter approach (std::vector<int, MyAlloc>) bakes the allocator into the container's type, which is fast but rigid. C++17 added std::pmr (polymorphic memory resources) to fix that: a std::pmr::memory_resource is a base class with virtual do_allocate / do_deallocate, and std::pmr containers hold a pointer to one. Now the allocation strategy is chosen at run time through a virtual call, so a std::pmr::vector<int> using a monotonic_buffer_resource over a stack array can be passed to ordinary code without the allocator infecting its type.
Why it matters: custom allocators let you replace many small global-heap calls with one cheap bump-pointer allocation from an arena, eliminating per-allocation overhead and fragmentation on a hot path — a real lever for latency-sensitive systems. The honest costs: the classic Allocator concept is notoriously fiddly to implement by hand (which is exactly why pmr exists), pmr's virtual dispatch reintroduces a small per-allocation indirection (a deliberate trade for flexibility), and you remain responsible for the lifetime of the underlying memory resource — a container must not outlive the buffer or arena its allocator draws from.
std::byte buf[4096]; std::pmr::monotonic_buffer_resource r{buf, sizeof buf}; std::pmr::vector<int> v{&r}; // v allocates from buf, not the global heap
The vector draws all its storage from a 4 KiB stack buffer via a polymorphic memory resource — no malloc() calls on this path.
A pmr container holds a non-owning pointer to its memory_resource, so the resource (and any buffer it wraps) must outlive the container. Let the buffer go out of scope while the vector still lives and you have a dangling allocator — a use-after-free waiting to happen.