23 General utilities library [utilities]

23.12 Memory resources [mem.res]

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

A specialization of class template pmr​::​polymorphic_­allocator satisfies the Allocator requirements (Table 31).
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.
namespace std::pmr {
  template<class Tp> 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& rhs) = delete;

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

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

    template<class T1, class T2, class... Args1, class... Args2>
      void construct(pair<T1, T2>* p, piecewise_construct_t,
                     tuple<Args1...> x, tuple<Args2...> y);
    template<class T1, class T2>
      void construct(pair<T1, T2>* p);
    template<class T1, class T2, class U, class V>
      void construct(pair<T1, T2>* p, U&& x, V&& y);
    template<class T1, class T2, class U, class V>
      void construct(pair<T1, T2>* p, const pair<U, V>& pr);
    template<class T1, class T2, class U, class V>
      void construct(pair<T1, T2>* p, pair<U, V>&& pr);

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

    polymorphic_allocator select_on_container_copy_construction() const;

    memory_resource* resource() const;
  };
}

23.12.3.1 polymorphic_­allocator constructors [mem.poly.allocator.ctor]

polymorphic_allocator() noexcept;
Effects: Sets memory_­rsrc to get_­default_­resource().
polymorphic_allocator(memory_resource* r);
Requires: 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().

23.12.3.2 polymorphic_­allocator member functions [mem.poly.allocator.mem]

[[nodiscard]] Tp* allocate(size_t n);
Effects: Equivalent to:
return static_cast<Tp*>(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp)));
void deallocate(Tp* p, size_t n);
Requires: 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.
template<class T, class... Args> void construct(T* p, Args&&... args);
Requires: Uses-allocator construction of T with allocator *this (see [allocator.uses.construction]) and constructor arguments std​::​forward<Args>(args)... is well-formed.
[Note
:
Uses-allocator construction is always well-formed for types that do not use allocators.
end note
]
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.
Remarks: This function shall not participate in overload resolution if T is a specialization of pair.
template<class T1, class T2, class... Args1, class... Args2> void construct(pair<T1, T2>* p, piecewise_construct_t, tuple<Args1...> x, tuple<Args2...> y);
[Note
:
This member function and the construct member functions that follow are overloads for piecewise construction of pairs ([pairs.pair]).
end note
]
Effects: Let xprime be a tuple constructed from x according to the appropriate rule from the following list.
[Note
:
The following description can be summarized as constructing a pair<T1, T2> object in the storage whose address is represented by p, as if by separate uses-allocator construction with allocator *this ([allocator.uses.construction]) of p->first using the elements of x and p->second using the elements of y.
end note
]
  • If uses_­allocator_­v<T1,polymorphic_­allocator> is false
    and is_­constructible_­v<T1,Args1...> is true,
    then xprime is x.
  • Otherwise, if uses_­allocator_­v<T1,polymorphic_­allocator> is true
    and is_­constructible_­v<T1,allocator_­arg_­t,polymorphic_­allocator,Args1...> is true,
    then xprime is tuple_­cat(make_­tuple(allocator_­arg, *this), std​::​move(x)).
  • Otherwise, if uses_­allocator_­v<T1,polymorphic_­allocator> is true
    and is_­constructible_­v<T1,Args1...,polymorphic_­allocator> is true,
    then xprime is tuple_­cat(std​::​move(x), make_­tuple(*this)).
  • Otherwise the program is ill formed.
Let yprime be a tuple constructed from y according to the appropriate rule from the following list:
  • If uses_­allocator_­v<T2,polymorphic_­allocator> is false
    and is_­constructible_­v<T2,Args2...> is true,
    then yprime is y.
  • Otherwise, if uses_­allocator_­v<T2,polymorphic_­allocator> is true
    and is_­constructible_­v<T2,allocator_­arg_­t,polymorphic_­allocator,Args2...> is true,
    then yprime is tuple_­cat(make_­tuple(allocator_­arg, *this), std​::​move(y)).
  • Otherwise, if uses_­allocator_­v<T2,polymorphic_­allocator> is true
    and is_­constructible_­v<T2,Args2...,polymorphic_­allocator> is true,
    then yprime is tuple_­cat(std​::​move(y), make_­tuple(*this)).
  • Otherwise the program is ill formed.
Then, using piecewise_­construct, xprime, and yprime as the constructor arguments, this function constructs a pair<T1, T2> object in the storage whose address is represented by p.
template<class T1, class T2> void construct(pair<T1, T2>* p);
Effects: Equivalent to:
construct(p, piecewise_construct, tuple<>(), tuple<>());
template<class T1, class T2, class U, class V> void construct(pair<T1, T2>* p, U&& x, V&& y);
Effects: Equivalent to:
construct(p, piecewise_construct,
          forward_as_tuple(std::forward<U>(x)),
          forward_as_tuple(std::forward<V>(y)));
template<class T1, class T2, class U, class V> void construct(pair<T1, T2>* p, const pair<U, V>& pr);
Effects: Equivalent to:
construct(p, piecewise_construct,
          forward_as_tuple(pr.first),
          forward_as_tuple(pr.second));
template<class T1, class T2, class U, class V> void construct(pair<T1, T2>* p, pair<U, V>&& pr);
Effects: Equivalent to:
construct(p, piecewise_construct,
          forward_as_tuple(std::forward<U>(pr.first)),
          forward_as_tuple(std::forward<V>(pr.second)));
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.

23.12.3.3 polymorphic_­allocator 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().
template<class T1, class T2> bool operator!=(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) noexcept;
Returns: !(a == b).