API Reference — pma/PolyAllocator
max_align_of<T, U>
Pick the stricter of two alignment requirements at compile time via max_align_of<T, U>::type.
Why this exists
When an allocator must satisfy the alignment of both the element type T and an architectural minimum (captured as min_align_t), choosing the larger alignment requires a compile-time branch. max_align_of encodes that branch as a metafunction so PolyAllocator's default alignment template argument can be derived automatically without runtime overhead. The result type is whichever of T or U has the larger alignof value.
Fields
| Name | Type | Description |
|---|---|---|
type |
T or U |
required — the type with the greater alignment; resolved at compile time via std::conditional |
min_align_t
Internal sentinel type representing the minimum alignment guarantee: the natural alignment of a pointer.
Why this exists
Allocators that support configurable alignment need a safe lower bound to fall back on when no explicit alignment is requested. Rather than hard-coding sizeof(void*) at every call site, min_align_t encodes that lower bound as a type so that max_align_of<T, min_align_t> can compute the right alignment automatically. This keeps the alignment floor in one place, making it easy to adjust across the entire pma allocator layer.
template<typename T, std::size_t Alignment = alignof(max_align_of<T, min_align_t>::type), class TDefaultMemoryResource = DefaultMemoryResource> class PolyAllocator
Delegate all memory operations to a swappable MemoryResource, letting you control the allocation strategy for any standard container without changing container code.
When to use this
Reach for PolyAllocator when you need a standard-library-compatible allocator whose backing memory resource can be injected at construction time — for example, to point a std::vector at a pool allocator or arena during a performance-critical phase. Use the default constructor when a global DefaultMemoryResource is sufficient; pass an explicit MemoryResource* to override it per-container.
Example
// Point a vector at a custom pool allocator
pma::PolyAllocator<float> poolAlloc{myPoolMemoryResource};
std::vector<float, pma::PolyAllocator<float>> weights(poolAlloc);
weights.resize(1024); // allocations come from myPoolMemoryResource
// Use default resource (static DefaultMemoryResource)
pma::PolyAllocator<int> defaultAlloc;
std::vector<int, pma::PolyAllocator<int>> indices(defaultAlloc);
Parameters
| Name | Type | Description |
|---|---|---|
T |
type parameter | required — the element type to allocate |
Alignment |
std::size_t |
optional — allocation alignment; defaults to alignof(max_align_of<T, min_align_t>::type) |
TDefaultMemoryResource |
type parameter | optional — fallback resource type instantiated as a static local when no resource is supplied; defaults to DefaultMemoryResource |
memRes |
MemoryResource* |
optional (constructor) — memory resource to use; if nullptr, the default resource is used instead |
Watch out for
- The default
MemoryResourceis a static local inside the default constructor, created once per<T, Alignment, TDefaultMemoryResource>instantiation. Its destructor runs at program exit. Clang's-Wexit-time-destructorswarning is explicitly suppressed here; be aware of destruction ordering if your program relies on destructor sequencing. - Passing
nullptrexplicitly is equivalent to the default constructor — it does not disable allocation; it selects the static default resource. - The outer
pma::PolyAllocatorinherits fromstd::scoped_allocator_adaptor, meaning nested containers (e.g.,std::vector<std::string>) automatically propagate the same resource to their inner allocators. If you want independent resources per nesting level, do not use the scoped adaptor directly.
Constraints
- Thread safety of allocations depends entirely on the supplied
MemoryResource. The allocator wrapper itself performs no synchronization.
rebind<U>
Produce a PolyAllocator for a different element type U while preserving the original alignment and TDefaultMemoryResource policy.
Why this exists
Standard library containers such as std::list and std::map internally allocate node types that differ from the user-facing element type. The rebind mechanism is how the standard mandates that an allocator expose a way to clone itself for these internal types. Without rebind, containers that need to allocate auxiliary objects alongside T cannot use a typed allocator. PolyAllocator::rebind<U>::other satisfies that contract by keeping the same resource and alignment while changing only the element type.
Fields
| Name | Type | Description |
|---|---|---|
other |
PolyAllocator<U, Alignment, TDefaultMemoryResource> |
required — the rebound allocator type for element type U |
Relationships
PolyAllocator— the outer class that declares this struct;rebindis always accessed asPolyAllocator<T,...>::rebind<U>::otherstd::allocator_traits— the standard trait layer that queriesrebind::otheron behalf of containers
TDefaultMemoryResource
Template policy parameter that specifies the concrete MemoryResource type instantiated as a static fallback when PolyAllocator is default-constructed.
Why this exists
PolyAllocator needs a safe default when no MemoryResource* is supplied at construction. Rather than hard-wiring a specific allocator type, the default resource type is a template parameter. This lets library users substitute their own global allocator (e.g., a thread-local pool or a debug-tracking allocator) without modifying PolyAllocator itself. The default value is DefaultMemoryResource.
Relationships
PolyAllocator— the template class that uses this parameter as its static fallback resource typeMemoryResource— the base interface thatTDefaultMemoryResourcemust satisfy