20 General utilities library [utilities]

20.12 Memory resources [mem.res]

20.12.3 Class template polymorphic_­allocator [mem.poly.allocator.class]

A specialization of class template pmr​::​polymorphic_­allocator meets the Cpp17Allocator requirements (Table 36).
Constructed with different memory resources, different instances of the same specialization of pmr​::​polymorphic_­allocator can exhibit entirely different allocation behavior.
This runtime polymorphism allows objects that use polymorphic_­allocator to behave as if they used different allocator types at run time even though they use the same static allocator type.
All specializations of class template pmr​::​polymorphic_­allocator meet the allocator completeness requirements ([allocator.requirements.completeness]).
namespace std::pmr {
  template<class Tp = byte> class polymorphic_allocator {
    memory_resource* memory_rsrc;       // exposition only

  public:
    using value_type = Tp;

    // [mem.poly.allocator.ctor], constructors
    polymorphic_allocator() noexcept;
    polymorphic_allocator(memory_resource* r);

    polymorphic_allocator(const polymorphic_allocator& other) = default;

    template<class U>
      polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;

    polymorphic_allocator& operator=(const polymorphic_allocator&) = delete;

    // [mem.poly.allocator.mem], member functions
    [[nodiscard]] Tp* allocate(size_t n);
    void deallocate(Tp* p, size_t n);

    [[nodiscard]] void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t));
    void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t));
    template<class T> [[nodiscard]] T* allocate_object(size_t n = 1);
    template<class T> void deallocate_object(T* p, size_t n = 1);
    template<class T, class... CtorArgs> [[nodiscard]] T* new_object(CtorArgs&&... ctor_args);
    template<class T> void delete_object(T* p);

    template<class T, class... Args>
      void construct(T* p, Args&&... args);

    template<class T>
      void destroy(T* p);

    polymorphic_allocator select_on_container_copy_construction() const;

    memory_resource* resource() const;
  };
}

20.12.3.1 Constructors [mem.poly.allocator.ctor]

polymorphic_allocator() noexcept;
Effects: Sets memory_­rsrc to get_­default_­resource().
polymorphic_allocator(memory_resource* r);
Preconditions: r is non-null.
Effects: Sets memory_­rsrc to r.
Throws: Nothing.
[Note
:
This constructor provides an implicit conversion from memory_­resource*.
— end note
]
template<class U> polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;
Effects: Sets memory_­rsrc to other.resource().

20.12.3.2 Member functions [mem.poly.allocator.mem]

[[nodiscard]] Tp* allocate(size_t n);
Effects: If numeric_­limits<size_­t>​::​max() / sizeof(Tp) < n, throws bad_­array_­new_­length.
Otherwise equivalent to:
return static_cast<Tp*>(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp)));
void deallocate(Tp* p, size_t n);
Preconditions: p was allocated from a memory resource x, equal to *memory_­rsrc, using x.allocate(n * sizeof(Tp), alignof(Tp)).
Effects: Equivalent to memory_­rsrc->deallocate(p, n * sizeof(Tp), alignof(Tp)).
Throws: Nothing.
[[nodiscard]] void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t));
Effects: Equivalent to: return memory_­rsrc->allocate(nbytes, alignment);
[Note
:
The return type is void* (rather than, e.g., byte*) to support conversion to an arbitrary pointer type U* by static_­cast<U*>, thus facilitating construction of a U object in the allocated memory.
— end note
]
void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t));
Effects: Equivalent to memory_­rsrc->deallocate(p, nbytes, alignment).
template<class T> [[nodiscard]] T* allocate_object(size_t n = 1);
Effects: Allocates memory suitable for holding an array of n objects of type T, as follows:
  • if numeric_­limits<size_­t>​::​max() / sizeof(T) < n, throws bad_­array_­new_­length,
  • otherwise equivalent to:
    return static_cast<T*>(allocate_bytes(n*sizeof(T), alignof(T)));
    
[Note
:
T is not deduced and must therefore be provided as a template argument.
— end note
]
template<class T> void deallocate_object(T* p, size_t n = 1);
Effects: Equivalent to deallocate_­bytes(p, n*sizeof(T), alignof(T)).
template<class T, class CtorArgs...> [[nodiscard]] T* new_object(CtorArgs&&... ctor_args);
Effects: Allocates and constructs an object of type T, as follows.

Equivalent to:
T* p = allocate_object<T>();
try {
  construct(p, std::forward<CtorArgs>(ctor_args)...);
} catch (...) {
  deallocate_object(p);
  throw;
}
return p;
[Note
:
T is not deduced and must therefore be provided as a template argument.
— end note
]
template<class T> void delete_object(T* p);
Effects: Equivalent to:
destroy(p);
deallocate_object(p);
template<class T, class... Args> void construct(T* p, Args&&... args);
Mandates: Uses-allocator construction of T with allocator *this (see [allocator.uses.construction]) and constructor arguments std​::​forward<Args>(args)... is well-formed.
Effects: Construct a T object in the storage whose address is represented by p by uses-allocator construction with allocator *this and constructor arguments std​::​forward<Args>(args)....
Throws: Nothing unless the constructor for T throws.
template<class T> void destroy(T* p);
Effects: As if by p->~T().
polymorphic_allocator select_on_container_copy_construction() const;
Returns: polymorphic_­allocator().
[Note
:
The memory resource is not propagated.
— end note
]
memory_resource* resource() const;
Returns: memory_­rsrc.

20.12.3.3 Equality [mem.poly.allocator.eq]

template<class T1, class T2> bool operator==(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) noexcept;
Returns: *a.resource() == *b.resource().