20 Memory management library [mem]

20.1 General [mem.general]

This Clause describes components for memory management.
The following subclauses describe general memory management facilities, smart pointers, memory resources, and scoped allocators, as summarized in Table 44.
Table 44: Memory management library summary [tab:mem.summary]
Subclause
Header
Memory
<cstdlib>, <memory>
Smart pointers
<memory>
Memory resources
<memory_­resource>
Scoped allocators
<scoped_­allocator>

20.2 Memory [memory]

20.2.1 In general [memory.general]

Subclause [memory] describes the contents of the header <memory> and some of the contents of the header <cstdlib>.

20.2.2 Header <memory> synopsis [memory.syn]

The header <memory> defines several types and function templates that describe properties of pointers and pointer-like types, manage memory for containers and other template types, destroy objects, and construct objects in uninitialized memory buffers ([pointer.traits][specialized.addressof] and [specialized.algorithms]).
The header also defines the templates unique_­ptr, shared_­ptr, weak_­ptr, out_­ptr_­t, inout_­ptr_­t, and various function templates that operate on objects of these types ([smartptr]).
Let POINTER_­OF(T) denote a type that is
  • T​::​pointer if the qualified-id T​::​pointer is valid and denotes a type,
  • otherwise, T​::​element_­type* if the qualified-id T​::​element_­type is valid and denotes a type,
  • otherwise, pointer_­traits<T>​::​element_­type*.
Let POINTER_­OF_­OR(T, U) denote a type that is:
  • POINTER_­OF(T) if POINTER_­OF(T) is valid and denotes a type,
  • otherwise, U.
#include <compare> // see [compare.syn] namespace std { // [pointer.traits], pointer traits template<class Ptr> struct pointer_traits; template<class T> struct pointer_traits<T*>; // [pointer.conversion], pointer conversion template<class T> constexpr T* to_address(T* p) noexcept; template<class Ptr> constexpr auto to_address(const Ptr& p) noexcept; // [ptr.align], pointer alignment void* align(size_t alignment, size_t size, void*& ptr, size_t& space); template<size_t N, class T> [[nodiscard]] constexpr T* assume_aligned(T* ptr); // [allocator.tag], allocator argument tag struct allocator_arg_t { explicit allocator_arg_t() = default; }; inline constexpr allocator_arg_t allocator_arg{}; // [allocator.uses], uses_­allocator template<class T, class Alloc> struct uses_allocator; // [allocator.uses.trait], uses_­allocator template<class T, class Alloc> inline constexpr bool uses_allocator_v = uses_allocator<T, Alloc>::value; // [allocator.uses.construction], uses-allocator construction template<class T, class Alloc, class... Args> constexpr auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) noexcept; template<class T, class Alloc, class Tuple1, class Tuple2> constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, Tuple1&& x, Tuple2&& y) noexcept; template<class T, class Alloc> constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) noexcept; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair<U, V>& pr) noexcept; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair<U, V>& pr) noexcept; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair<U, V>&& pr) noexcept; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair<U, V>&& pr) noexcept; template<class T, class Alloc, class U> constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u) noexcept; template<class T, class Alloc, class... Args> constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); template<class T, class Alloc, class... Args> constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args); // [allocator.traits], allocator traits template<class Alloc> struct allocator_traits; template<class Pointer> struct allocation_result { Pointer ptr; size_t count; }; template<class Allocator> [[nodiscard]] constexpr allocation_result<typename allocator_traits<Allocator>::pointer> allocate_at_least(Allocator& a, size_t n); // [default.allocator], the default allocator template<class T> class allocator; template<class T, class U> constexpr bool operator==(const allocator<T>&, const allocator<U>&) noexcept; // [specialized.addressof], addressof template<class T> constexpr T* addressof(T& r) noexcept; template<class T> const T* addressof(const T&&) = delete; // [specialized.algorithms], specialized algorithms // [special.mem.concepts], special memory concepts template<class I> concept nothrow-input-iterator = see below; // exposition only template<class I> concept nothrow-forward-iterator = see below; // exposition only template<class S, class I> concept nothrow-sentinel-for = see below; // exposition only template<class R> concept nothrow-input-range = see below; // exposition only template<class R> concept nothrow-forward-range = see below; // exposition only template<class NoThrowForwardIterator> void uninitialized_default_construct(NoThrowForwardIterator first, NoThrowForwardIterator last); template<class ExecutionPolicy, class NoThrowForwardIterator> void uninitialized_default_construct(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] NoThrowForwardIterator first, NoThrowForwardIterator last); template<class NoThrowForwardIterator, class Size> NoThrowForwardIterator uninitialized_default_construct_n(NoThrowForwardIterator first, Size n); template<class ExecutionPolicy, class NoThrowForwardIterator, class Size> NoThrowForwardIterator uninitialized_default_construct_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] NoThrowForwardIterator first, Size n); namespace ranges { template<nothrow-forward-iterator I, nothrow-sentinel-for<I> S> requires default_­initializable<iter_value_t<I>> I uninitialized_default_construct(I first, S last); template<nothrow-forward-range R> requires default_­initializable<range_value_t<R>> borrowed_iterator_t<R> uninitialized_default_construct(R&& r); template<nothrow-forward-iterator I> requires default_­initializable<iter_value_t<I>> I uninitialized_default_construct_n(I first, iter_difference_t<I> n); } template<class NoThrowForwardIterator> void uninitialized_value_construct(NoThrowForwardIterator first, NoThrowForwardIterator last); template<class ExecutionPolicy, class NoThrowForwardIterator> void uninitialized_value_construct(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] NoThrowForwardIterator first, NoThrowForwardIterator last); template<class NoThrowForwardIterator, class Size> NoThrowForwardIterator uninitialized_value_construct_n(NoThrowForwardIterator first, Size n); template<class ExecutionPolicy, class NoThrowForwardIterator, class Size> NoThrowForwardIterator uninitialized_value_construct_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] NoThrowForwardIterator first, Size n); namespace ranges { template<nothrow-forward-iterator I, nothrow-sentinel-for<I> S> requires default_­initializable<iter_value_t<I>> I uninitialized_value_construct(I first, S last); template<nothrow-forward-range R> requires default_­initializable<range_value_t<R>> borrowed_iterator_t<R> uninitialized_value_construct(R&& r); template<nothrow-forward-iterator I> requires default_­initializable<iter_value_t<I>> I uninitialized_value_construct_n(I first, iter_difference_t<I> n); } template<class InputIterator, class NoThrowForwardIterator> NoThrowForwardIterator uninitialized_copy(InputIterator first, InputIterator last, NoThrowForwardIterator result); template<class ExecutionPolicy, class ForwardIterator, class NoThrowForwardIterator> NoThrowForwardIterator uninitialized_copy(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] ForwardIterator first, ForwardIterator last, NoThrowForwardIterator result); template<class InputIterator, class Size, class NoThrowForwardIterator> NoThrowForwardIterator uninitialized_copy_n(InputIterator first, Size n, NoThrowForwardIterator result); template<class ExecutionPolicy, class ForwardIterator, class Size, class NoThrowForwardIterator> NoThrowForwardIterator uninitialized_copy_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] ForwardIterator first, Size n, NoThrowForwardIterator result); namespace ranges { template<class I, class O> using uninitialized_copy_result = in_out_result<I, O>; template<input_­iterator I, sentinel_­for<I> S1, nothrow-forward-iterator O, nothrow-sentinel-for<O> S2> requires constructible_­from<iter_value_t<O>, iter_reference_t<I>> uninitialized_copy_result<I, O> uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); template<input_­range IR, nothrow-forward-range OR> requires constructible_­from<range_value_t<OR>, range_reference_t<IR>> uninitialized_copy_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>> uninitialized_copy(IR&& in_range, OR&& out_range); template<class I, class O> using uninitialized_copy_n_result = in_out_result<I, O>; template<input_­iterator I, nothrow-forward-iterator O, nothrow-sentinel-for<O> S> requires constructible_­from<iter_value_t<O>, iter_reference_t<I>> uninitialized_copy_n_result<I, O> uninitialized_copy_n(I ifirst, iter_difference_t<I> n, O ofirst, S olast); } template<class InputIterator, class NoThrowForwardIterator> NoThrowForwardIterator uninitialized_move(InputIterator first, InputIterator last, NoThrowForwardIterator result); template<class ExecutionPolicy, class ForwardIterator, class NoThrowForwardIterator> NoThrowForwardIterator uninitialized_move(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] ForwardIterator first, ForwardIterator last, NoThrowForwardIterator result); template<class InputIterator, class Size, class NoThrowForwardIterator> pair<InputIterator, NoThrowForwardIterator> uninitialized_move_n(InputIterator first, Size n, NoThrowForwardIterator result); template<class ExecutionPolicy, class ForwardIterator, class Size, class NoThrowForwardIterator> pair<ForwardIterator, NoThrowForwardIterator> uninitialized_move_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] ForwardIterator first, Size n, NoThrowForwardIterator result); namespace ranges { template<class I, class O> using uninitialized_move_result = in_out_result<I, O>; template<input_­iterator I, sentinel_­for<I> S1, nothrow-forward-iterator O, nothrow-sentinel-for<O> S2> requires constructible_­from<iter_value_t<O>, iter_rvalue_reference_t<I>> uninitialized_move_result<I, O> uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast); template<input_­range IR, nothrow-forward-range OR> requires constructible_­from<range_value_t<OR>, range_rvalue_reference_t<IR>> uninitialized_move_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>> uninitialized_move(IR&& in_range, OR&& out_range); template<class I, class O> using uninitialized_move_n_result = in_out_result<I, O>; template<input_­iterator I, nothrow-forward-iterator O, nothrow-sentinel-for<O> S> requires constructible_­from<iter_value_t<O>, iter_rvalue_reference_t<I>> uninitialized_move_n_result<I, O> uninitialized_move_n(I ifirst, iter_difference_t<I> n, O ofirst, S olast); } template<class NoThrowForwardIterator, class T> void uninitialized_fill(NoThrowForwardIterator first, NoThrowForwardIterator last, const T& x); template<class ExecutionPolicy, class NoThrowForwardIterator, class T> void uninitialized_fill(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] NoThrowForwardIterator first, NoThrowForwardIterator last, const T& x); template<class NoThrowForwardIterator, class Size, class T> NoThrowForwardIterator uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); template<class ExecutionPolicy, class NoThrowForwardIterator, class Size, class T> NoThrowForwardIterator uninitialized_fill_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] NoThrowForwardIterator first, Size n, const T& x); namespace ranges { template<nothrow-forward-iterator I, nothrow-sentinel-for<I> S, class T> requires constructible_­from<iter_value_t<I>, const T&> I uninitialized_fill(I first, S last, const T& x); template<nothrow-forward-range R, class T> requires constructible_­from<range_value_t<R>, const T&> borrowed_iterator_t<R> uninitialized_fill(R&& r, const T& x); template<nothrow-forward-iterator I, class T> requires constructible_­from<iter_value_t<I>, const T&> I uninitialized_fill_n(I first, iter_difference_t<I> n, const T& x); } // [specialized.construct], construct_­at template<class T, class... Args> constexpr T* construct_at(T* location, Args&&... args); namespace ranges { template<class T, class... Args> constexpr T* construct_at(T* location, Args&&... args); } // [specialized.destroy], destroy template<class T> constexpr void destroy_at(T* location); template<class NoThrowForwardIterator> constexpr void destroy(NoThrowForwardIterator first, NoThrowForwardIterator last); template<class ExecutionPolicy, class NoThrowForwardIterator> void destroy(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] NoThrowForwardIterator first, NoThrowForwardIterator last); template<class NoThrowForwardIterator, class Size> constexpr NoThrowForwardIterator destroy_n(NoThrowForwardIterator first, Size n); template<class ExecutionPolicy, class NoThrowForwardIterator, class Size> NoThrowForwardIterator destroy_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads] NoThrowForwardIterator first, Size n); namespace ranges { template<destructible T> constexpr void destroy_at(T* location) noexcept; template<nothrow-input-iterator I, nothrow-sentinel-for<I> S> requires destructible<iter_value_t<I>> constexpr I destroy(I first, S last) noexcept; template<nothrow-input-range R> requires destructible<range_value_t<R>> constexpr borrowed_iterator_t<R> destroy(R&& r) noexcept; template<nothrow-input-iterator I> requires destructible<iter_value_t<I>> constexpr I destroy_n(I first, iter_difference_t<I> n) noexcept; } // [unique.ptr], class template unique_­ptr template<class T> struct default_delete; template<class T> struct default_delete<T[]>; template<class T, class D = default_delete<T>> class unique_ptr; template<class T, class D> class unique_ptr<T[], D>; template<class T, class... Args> constexpr unique_ptr<T> make_unique(Args&&... args); // T is not array template<class T> constexpr unique_ptr<T> make_unique(size_t n); // T is U[] template<class T, class... Args> unspecified make_unique(Args&&...) = delete; // T is U[N] template<class T> constexpr unique_ptr<T> make_unique_for_overwrite(); // T is not array template<class T> constexpr unique_ptr<T> make_unique_for_overwrite(size_t n); // T is U[] template<class T, class... Args> unspecified make_unique_for_overwrite(Args&&...) = delete; // T is U[N] template<class T, class D> constexpr void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) noexcept; template<class T1, class D1, class T2, class D2> constexpr bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template<class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template<class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template<class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template<class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template<class T1, class D1, class T2, class D2> requires three_­way_­comparable_­with<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer> compare_three_way_result_t<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer> operator<=>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template<class T, class D> constexpr bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept; template<class T, class D> constexpr bool operator<(const unique_ptr<T, D>& x, nullptr_t); template<class T, class D> constexpr bool operator<(nullptr_t, const unique_ptr<T, D>& y); template<class T, class D> constexpr bool operator>(const unique_ptr<T, D>& x, nullptr_t); template<class T, class D> constexpr bool operator>(nullptr_t, const unique_ptr<T, D>& y); template<class T, class D> constexpr bool operator<=(const unique_ptr<T, D>& x, nullptr_t); template<class T, class D> constexpr bool operator<=(nullptr_t, const unique_ptr<T, D>& y); template<class T, class D> constexpr bool operator>=(const unique_ptr<T, D>& x, nullptr_t); template<class T, class D> constexpr bool operator>=(nullptr_t, const unique_ptr<T, D>& y); template<class T, class D> requires three_­way_­comparable<typename unique_ptr<T, D>::pointer> constexpr compare_three_way_result_t<typename unique_ptr<T, D>::pointer> operator<=>(const unique_ptr<T, D>& x, nullptr_t); template<class E, class T, class Y, class D> basic_ostream<E, T>& operator<<(basic_ostream<E, T>& os, const unique_ptr<Y, D>& p); // [util.smartptr.weak.bad], class bad_­weak_­ptr class bad_weak_ptr; // [util.smartptr.shared], class template shared_­ptr template<class T> class shared_ptr; // [util.smartptr.shared.create], shared_­ptr creation template<class T, class... Args> shared_ptr<T> make_shared(Args&&... args); // T is not array template<class T, class A, class... Args> shared_ptr<T> allocate_shared(const A& a, Args&&... args); // T is not array template<class T> shared_ptr<T> make_shared(size_t N); // T is U[] template<class T, class A> shared_ptr<T> allocate_shared(const A& a, size_t N); // T is U[] template<class T> shared_ptr<T> make_shared(); // T is U[N] template<class T, class A> shared_ptr<T> allocate_shared(const A& a); // T is U[N] template<class T> shared_ptr<T> make_shared(size_t N, const remove_extent_t<T>& u); // T is U[] template<class T, class A> shared_ptr<T> allocate_shared(const A& a, size_t N, const remove_extent_t<T>& u); // T is U[] template<class T> shared_ptr<T> make_shared(const remove_extent_t<T>& u); // T is U[N] template<class T, class A> shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& u); // T is U[N] template<class T> shared_ptr<T> make_shared_for_overwrite(); // T is not U[] template<class T, class A> shared_ptr<T> allocate_shared_for_overwrite(const A& a); // T is not U[] template<class T> shared_ptr<T> make_shared_for_overwrite(size_t N); // T is U[] template<class T, class A> shared_ptr<T> allocate_shared_for_overwrite(const A& a, size_t N); // T is U[] // [util.smartptr.shared.cmp], shared_­ptr comparisons template<class T, class U> bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> strong_ordering operator<=>(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T> bool operator==(const shared_ptr<T>& x, nullptr_t) noexcept; template<class T> strong_ordering operator<=>(const shared_ptr<T>& x, nullptr_t) noexcept; // [util.smartptr.shared.spec], shared_­ptr specialized algorithms template<class T> void swap(shared_ptr<T>& a, shared_ptr<T>& b) noexcept; // [util.smartptr.shared.cast], shared_­ptr casts template<class T, class U> shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U>&& r) noexcept; template<class T, class U> shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> dynamic_pointer_cast(shared_ptr<U>&& r) noexcept; template<class T, class U> shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> const_pointer_cast(shared_ptr<U>&& r) noexcept; template<class T, class U> shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U>&& r) noexcept; // [util.smartptr.getdeleter], shared_­ptr get_­deleter template<class D, class T> D* get_deleter(const shared_ptr<T>& p) noexcept; // [util.smartptr.shared.io], shared_­ptr I/O template<class E, class T, class Y> basic_ostream<E, T>& operator<<(basic_ostream<E, T>& os, const shared_ptr<Y>& p); // [util.smartptr.weak], class template weak_­ptr template<class T> class weak_ptr; // [util.smartptr.weak.spec], weak_­ptr specialized algorithms template<class T> void swap(weak_ptr<T>& a, weak_ptr<T>& b) noexcept; // [util.smartptr.ownerless], class template owner_­less template<class T = void> struct owner_less; // [util.smartptr.enab], class template enable_­shared_­from_­this template<class T> class enable_shared_from_this; // [util.smartptr.hash], hash support template<class T> struct hash; template<class T, class D> struct hash<unique_ptr<T, D>>; template<class T> struct hash<shared_ptr<T>>; // [util.smartptr.atomic], atomic smart pointers template<class T> struct atomic; template<class T> struct atomic<shared_ptr<T>>; template<class T> struct atomic<weak_ptr<T>>; // [out.ptr.t], class template out_­ptr_­t template<class Smart, class Pointer, class... Args> class out_ptr_t; // [out.ptr], function template out_­ptr template<class Pointer = void, class Smart, class... Args> auto out_ptr(Smart& s, Args&&... args); // [inout.ptr.t], class template inout_­ptr_­t template<class Smart, class Pointer, class... Args> class inout_ptr_t; // [inout.ptr], function template inout_­ptr template<class Pointer = void, class Smart, class... Args> auto inout_ptr(Smart& s, Args&&... args); }

20.2.3 Pointer traits [pointer.traits]

20.2.3.1 General [pointer.traits.general]

The class template pointer_­traits supplies a uniform interface to certain attributes of pointer-like types.
namespace std { template<class Ptr> struct pointer_traits { using pointer = Ptr; using element_type = see below; using difference_type = see below; template<class U> using rebind = see below; static pointer pointer_to(see below r); }; template<class T> struct pointer_traits<T*> { using pointer = T*; using element_type = T; using difference_type = ptrdiff_t; template<class U> using rebind = U*; static constexpr pointer pointer_to(see below r) noexcept; }; }

20.2.3.2 Member types [pointer.traits.types]

using element_type = see below;
Type: Ptr​::​element_­type if the qualified-id Ptr​::​element_­type is valid and denotes a type ([temp.deduct]); otherwise, T if Ptr is a class template instantiation of the form SomePointer<T, Args>, where Args is zero or more type arguments; otherwise, the specialization is ill-formed.
using difference_type = see below;
Type: Ptr​::​difference_­type if the qualified-id Ptr​::​difference_­type is valid and denotes a type ([temp.deduct]); otherwise, ptrdiff_­t.
template<class U> using rebind = see below;
Alias template: Ptr​::​rebind<U> if the qualified-id Ptr​::​rebind<U> is valid and denotes a type ([temp.deduct]); otherwise, SomePointer<U, Args> if Ptr is a class template instantiation of the form SomePointer<T, Args>, where Args is zero or more type arguments; otherwise, the instantiation of rebind is ill-formed.

20.2.3.3 Member functions [pointer.traits.functions]

static pointer pointer_traits::pointer_to(see below r); static constexpr pointer pointer_traits<T*>::pointer_to(see below r) noexcept;
Mandates: For the first member function, Ptr​::​pointer_­to(r) is well-formed.
Preconditions: For the first member function, Ptr​::​pointer_­to(r) returns a pointer to r through which indirection is valid.
Returns: The first member function returns Ptr​::​pointer_­to(r).
The second member function returns addressof(r).
Remarks: If element_­type is cv void, the type of r is unspecified; otherwise, it is element_­type&.

20.2.3.4 Optional members [pointer.traits.optmem]

Specializations of pointer_­traits may define the member declared in this subclause to customize the behavior of the standard library.
static element_type* to_address(pointer p) noexcept;
Returns: A pointer of type element_­type* that references the same location as the argument p.
[Note 1:
This function is intended to be the inverse of pointer_­to.
If defined, it customizes the behavior of the non-member function to_­address ([pointer.conversion]).
— end note]

20.2.4 Pointer conversion [pointer.conversion]

template<class T> constexpr T* to_address(T* p) noexcept;
Mandates: T is not a function type.
Returns: p.
template<class Ptr> constexpr auto to_address(const Ptr& p) noexcept;
Returns: pointer_­traits<Ptr>​::​to_­address(p) if that expression is well-formed (see [pointer.traits.optmem]), otherwise to_­address(p.operator->()).

20.2.5 Pointer alignment [ptr.align]

void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
Preconditions:
  • alignment is a power of two
  • ptr represents the address of contiguous storage of at least space bytes
Effects: If it is possible to fit size bytes of storage aligned by alignment into the buffer pointed to by ptr with length space, the function updates ptr to represent the first possible address of such storage and decreases space by the number of bytes used for alignment.
Otherwise, the function does nothing.
Returns: A null pointer if the requested aligned buffer would not fit into the available space, otherwise the adjusted value of ptr.
[Note 1:
The function updates its ptr and space arguments so that it can be called repeatedly with possibly different alignment and size arguments for the same buffer.
— end note]
template<size_t N, class T> [[nodiscard]] constexpr T* assume_aligned(T* ptr);
Mandates: N is a power of two.
Preconditions: ptr points to an object X of a type similar ([conv.qual]) to T, where X has alignment N ([basic.align]).
Returns: ptr.
Throws: Nothing.
[Note 2:
The alignment assumption on an object X expressed by a call to assume_­aligned might result in generation of more efficient code.
It is up to the program to ensure that the assumption actually holds.
The call does not cause the implementation to verify or enforce this.
An implementation might only make the assumption for those operations on X that access X through the pointer returned by assume_­aligned.
— end note]

20.2.6 Allocator argument tag [allocator.tag]

namespace std { struct allocator_arg_t { explicit allocator_arg_t() = default; }; inline constexpr allocator_arg_t allocator_arg{}; }
The allocator_­arg_­t struct is an empty class type used as a unique type to disambiguate constructor and function overloading.
Specifically, several types (see tuple [tuple]) have constructors with allocator_­arg_­t as the first argument, immediately followed by an argument of a type that meets the Cpp17Allocator requirements ([allocator.requirements.general]).

20.2.7 uses_­allocator [allocator.uses]

20.2.7.1 uses_­allocator trait [allocator.uses.trait]

template<class T, class Alloc> struct uses_allocator;
Remarks: Automatically detects whether T has a nested allocator_­type that is convertible from Alloc.
Meets the Cpp17BinaryTypeTrait requirements ([meta.rqmts]).
The implementation shall provide a definition that is derived from true_­type if the qualified-id T​::​allocator_­type is valid and denotes a type ([temp.deduct]) and is_­convertible_­v<Alloc, T​::​allocator_­type> != false, otherwise it shall be derived from false_­type.
A program may specialize this template to derive from true_­type for a program-defined type T that does not have a nested allocator_­type but nonetheless can be constructed with an allocator where either:
  • the first argument of a constructor has type allocator_­arg_­t and the second argument has type Alloc or
  • the last argument of a constructor has type Alloc.

20.2.7.2 Uses-allocator construction [allocator.uses.construction]

Uses-allocator construction with allocator alloc and constructor arguments args... refers to the construction of an object of type T such that alloc is passed to the constructor of T if T uses an allocator type compatible with alloc.
When applied to the construction of an object of type T, it is equivalent to initializing it with the value of the expression make_­obj_­using_­allocator<T>(alloc, args...), described below.
The following utility functions support three conventions for passing alloc to a constructor:
  • If T does not use an allocator compatible with alloc, then alloc is ignored.
  • Otherwise, if T has a constructor invocable as T(allocator_­arg, alloc, args...) (leading-allocator convention), then uses-allocator construction chooses this constructor form.
  • Otherwise, if T has a constructor invocable as T(args..., alloc) (trailing-allocator convention), then uses-allocator construction chooses this constructor form.
The uses_­allocator_­construction_­args function template takes an allocator and argument list and produces (as a tuple) a new argument list matching one of the above conventions.
Additionally, overloads are provided that treat specializations of pair such that uses-allocator construction is applied individually to the first and second data members.
The make_­obj_­using_­allocator and uninitialized_­construct_­using_­allocator function templates apply the modified constructor arguments to construct an object of type T as a return value or in-place, respectively.
[Note 1:
For uses_­allocator_­construction_­args and make_­obj_­using_­allocator, type T is not deduced and must therefore be specified explicitly by the caller.
— end note]
template<class T, class Alloc, class... Args> constexpr auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) noexcept;
Constraints: T is not a specialization of pair.
Returns: A tuple value determined as follows:
  • If uses_­allocator_­v<T, Alloc> is false and is_­constructible_­v<T, Args...> is true, return forward_­as_­tuple(std​::​forward<Args>(args)...).
  • Otherwise, if uses_­allocator_­v<T, Alloc> is true and is_­constructible_­v<T, allocator_­arg_­t, const Alloc&, Args...> is true, return tuple<allocator_arg_t, const Alloc&, Args&&...>( allocator_arg, alloc, std::forward<Args>(args)...)
  • Otherwise, if uses_­allocator_­v<T, Alloc> is true and is_­constructible_­v<T, Args..., const Alloc&> is true, return forward_­as_­tuple(std​::​forward<Args>(args)..., alloc).
  • Otherwise, the program is ill-formed.
[Note 2:
This definition prevents a silent failure to pass the allocator to a constructor of a type for which uses_­allocator_­v<T, Alloc> is true.
— end note]
template<class T, class Alloc, class Tuple1, class Tuple2> constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, Tuple1&& x, Tuple2&& y) noexcept;
Constraints: T is a specialization of pair.
Effects: For T specified as pair<T1, T2>, equivalent to: return make_tuple( piecewise_construct, apply([&alloc](auto&&... args1) { return uses_allocator_construction_args<T1>( alloc, std::forward<decltype(args1)>(args1)...); }, std::forward<Tuple1>(x)), apply([&alloc](auto&&... args2) { return uses_allocator_construction_args<T2>( alloc, std::forward<decltype(args2)>(args2)...); }, std::forward<Tuple2>(y)));
template<class T, class Alloc> constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept;
Constraints: T is a specialization of pair.
Effects: Equivalent to: return uses_allocator_construction_args<T>(alloc, piecewise_construct, tuple<>{}, tuple<>{});
template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) noexcept;
Constraints: T is a specialization of pair.
Effects: Equivalent to: return uses_allocator_construction_args<T>(alloc, piecewise_construct, forward_as_tuple(std::forward<U>(u)), forward_as_tuple(std::forward<V>(v)));
template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair<U, V>& pr) noexcept; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair<U, V>& pr) noexcept;
Constraints: T is a specialization of pair.
Effects: Equivalent to: return uses_allocator_construction_args<T>(alloc, piecewise_construct, forward_as_tuple(pr.first), forward_as_tuple(pr.second));
template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair<U, V>&& pr) noexcept; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair<U, V>&& pr) noexcept;
Constraints: T is a specialization of pair.
Effects: Equivalent to: return uses_allocator_construction_args<T>(alloc, piecewise_construct, forward_as_tuple(get<0>(std::move(pr))), forward_as_tuple(get<1>(std::move(pr))));
template<class T, class Alloc, class U> constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u) noexcept;
Let FUN be the function template: template<class A, class B> void FUN(const pair<A, B>&);
Constraints: T is a specialization of pair, and the expression FUN(u) is not well-formed when considered as an unevaluated operand.
Let pair-constructor be an exposition-only class defined as follows:
class pair-constructor { using pair-type = remove_cv_t<T>; // exposition only constexpr auto do-construct(const pair-type& p) const { // exposition only return make_obj_using_allocator<pair-type>(alloc_, p); } constexpr auto do-construct(pair-type&& p) const { // exposition only return make_obj_using_allocator<pair-type>(alloc_, std::move(p)); } const Alloc& alloc_; // exposition only U& u_; // exposition only public: constexpr operator pair-type() const { return do-construct(std::forward<U>(u_)); } };
Returns: make_­tuple(pc), where pc is a pair-constructor object whose alloc_­ member is initialized with alloc and whose u_­ member is initialized with u.
template<class T, class Alloc, class... Args> constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args);
Effects: Equivalent to: return make_from_tuple<T>(uses_allocator_construction_args<T>( alloc, std::forward<Args>(args)...));
template<class T, class Alloc, class... Args> constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args);
Effects: Equivalent to: return apply([&]<class... U>(U&&... xs) { return construct_at(p, std::forward<U>(xs)...); }, uses_allocator_construction_args<T>(alloc, std::forward<Args>(args)...));

20.2.8 Allocator traits [allocator.traits]

20.2.8.1 General [allocator.traits.general]

The class template allocator_­traits supplies a uniform interface to all allocator types.
An allocator cannot be a non-class type, however, even if allocator_­traits supplies the entire required interface.
[Note 1:
Thus, it is always possible to create a derived class from an allocator.
— end note]
namespace std { template<class Alloc> struct allocator_traits { using allocator_type = Alloc; using value_type = typename Alloc::value_type; using pointer = see below; using const_pointer = see below; using void_pointer = see below; using const_void_pointer = see below; using difference_type = see below; using size_type = see below; using propagate_on_container_copy_assignment = see below; using propagate_on_container_move_assignment = see below; using propagate_on_container_swap = see below; using is_always_equal = see below; template<class T> using rebind_alloc = see below; template<class T> using rebind_traits = allocator_traits<rebind_alloc<T>>; [[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n); [[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint); static constexpr void deallocate(Alloc& a, pointer p, size_type n); template<class T, class... Args> static constexpr void construct(Alloc& a, T* p, Args&&... args); template<class T> static constexpr void destroy(Alloc& a, T* p); static constexpr size_type max_size(const Alloc& a) noexcept; static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs); }; }

20.2.8.2 Member types [allocator.traits.types]

using pointer = see below;
Type: Alloc​::​pointer if the qualified-id Alloc​::​pointer is valid and denotes a type ([temp.deduct]); otherwise, value_­type*.
using const_pointer = see below;
Type: Alloc​::​const_­pointer if the qualified-id Alloc​::​const_­pointer is valid and denotes a type ([temp.deduct]); otherwise, pointer_­traits<pointer>​::​rebind<const value_­type>.
using void_pointer = see below;
Type: Alloc​::​void_­pointer if the qualified-id Alloc​::​void_­pointer is valid and denotes a type ([temp.deduct]); otherwise, pointer_­traits<pointer>​::​rebind<void>.
using const_void_pointer = see below;
Type: Alloc​::​const_­void_­pointer if the qualified-id Alloc​::​const_­void_­pointer is valid and denotes a type ([temp.deduct]); otherwise, pointer_­traits<pointer>​::​​rebind<const void>.
using difference_type = see below;
Type: Alloc​::​difference_­type if the qualified-id Alloc​::​difference_­type is valid and denotes a type ([temp.deduct]); otherwise, pointer_­traits<pointer>​::​difference_­type.
using size_type = see below;
Type: Alloc​::​size_­type if the qualified-id Alloc​::​size_­type is valid and denotes a type ([temp.deduct]); otherwise, make_­unsigned_­t<difference_­type>.
using propagate_on_container_copy_assignment = see below;
Type: Alloc​::​propagate_­on_­container_­copy_­assignment if the qualified-id Alloc​::​propagate_­on_­container_­copy_­assignment is valid and denotes a type ([temp.deduct]); otherwise false_­type.
using propagate_on_container_move_assignment = see below;
Type: Alloc​::​propagate_­on_­container_­move_­assignment if the qualified-id Alloc​::​propagate_­on_­container_­move_­assignment is valid and denotes a type ([temp.deduct]); otherwise false_­type.
using propagate_on_container_swap = see below;
Type: Alloc​::​propagate_­on_­container_­swap if the qualified-id Alloc​::​propagate_­on_­container_­swap is valid and denotes a type ([temp.deduct]); otherwise false_­type.
using is_always_equal = see below;
Type: Alloc​::​is_­always_­equal if the qualified-id Alloc​::​is_­always_­equal is valid and denotes a type ([temp.deduct]); otherwise is_­empty<Alloc>​::​type.
template<class T> using rebind_alloc = see below;
Alias template: Alloc​::​rebind<T>​::​other if the qualified-id Alloc​::​rebind<T>​::​other is valid and denotes a type ([temp.deduct]); otherwise, Alloc<T, Args> if Alloc is a class template instantiation of the form Alloc<U, Args>, where Args is zero or more type arguments; otherwise, the instantiation of rebind_­alloc is ill-formed.

20.2.8.3 Static member functions [allocator.traits.members]

[[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n);
Returns: a.allocate(n).
[[nodiscard]] static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint);
Returns: a.allocate(n, hint) if that expression is well-formed; otherwise, a.allocate(n).
static constexpr void deallocate(Alloc& a, pointer p, size_type n);
Effects: Calls a.deallocate(p, n).
Throws: Nothing.
template<class T, class... Args> static constexpr void construct(Alloc& a, T* p, Args&&... args);
Effects: Calls a.construct(p, std​::​forward<Args>(args)...) if that call is well-formed; otherwise, invokes construct_­at(p, std​::​forward<Args>(args)...).
template<class T> static constexpr void destroy(Alloc& a, T* p);
Effects: Calls a.destroy(p) if that call is well-formed; otherwise, invokes destroy_­at(p).
static constexpr size_type max_size(const Alloc& a) noexcept;
Returns: a.max_­size() if that expression is well-formed; otherwise, numeric_­limits<size_­type>​::​​max()/sizeof(value_­type).
static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs);
Returns: rhs.select_­on_­container_­copy_­construction() if that expression is well-formed; otherwise, rhs.

20.2.8.4 Other [allocator.traits.other]

The class template allocation_­result has the template parameters, data members, and special members specified above.
It has no base classes or members other than those specified.
template<class Allocator> [[nodiscard]] constexpr allocation_result<typename allocator_traits<Allocator>::pointer> allocate_at_least(Allocator& a, size_t n);
Returns: a.allocate_­at_­least(n) if that expression is well-formed; otherwise, {a.allocate(n), n}.

20.2.9 The default allocator [default.allocator]

20.2.9.1 General [default.allocator.general]

All specializations of the default allocator meet the allocator completeness requirements ([allocator.requirements.completeness]).
namespace std { template<class T> class allocator { public: using value_type = T; using size_type = size_t; using difference_type = ptrdiff_t; using propagate_on_container_move_assignment = true_type; constexpr allocator() noexcept; constexpr allocator(const allocator&) noexcept; template<class U> constexpr allocator(const allocator<U>&) noexcept; constexpr ~allocator(); constexpr allocator& operator=(const allocator&) = default; [[nodiscard]] constexpr T* allocate(size_t n); [[nodiscard]] constexpr allocation_result<T*> allocate_at_least(size_t n); constexpr void deallocate(T* p, size_t n); }; }
allocator_­traits<allocator<T>>​::​is_­always_­equal​::​value is true for any T.

20.2.9.2 Members [allocator.members]

Except for the destructor, member functions of the default allocator shall not introduce data races ([intro.multithread]) as a result of concurrent calls to those member functions from different threads.
Calls to these functions that allocate or deallocate a particular unit of storage shall occur in a single total order, and each such deallocation call shall happen before the next allocation (if any) in this order.
[[nodiscard]] constexpr T* allocate(size_t n);
Mandates: T is not an incomplete type ([basic.types.general]).
Returns: A pointer to the initial element of an array of n T.
Throws: bad_­array_­new_­length if numeric_­limits<size_­t>​::​max() / sizeof(T) < n, or bad_­alloc if the storage cannot be obtained.
Remarks: The storage for the array is obtained by calling ​::​operator new ([new.delete]), but it is unspecified when or how often this function is called.
This function starts the lifetime of the array object, but not that of any of the array elements.
[[nodiscard]] constexpr allocation_result<T*> allocate_at_least(size_t n);
Mandates: T is not an incomplete type ([basic.types.general]).
Returns: allocation_­result<T*>{ptr, count}, where ptr is a pointer to the initial element of an array of count T and .
Throws: bad_­array_­new_­length if , or bad_­alloc if the storage cannot be obtained.
Remarks: The storage for the array is obtained by calling ​::​operator new, but it is unspecified when or how often this function is called.
This function starts the lifetime of the array object, but not that of any of the array elements.
constexpr void deallocate(T* p, size_t n);
Preconditions:
  • If p is memory that was obtained by a call to allocate_­at_­least, let ret be the value returned and req be the value passed as the first argument to that call.
    p is equal to ret.ptr and n is a value such that .
  • Otherwise, p is a pointer value obtained from allocate.
    n equals the value passed as the first argument to the invocation of allocate which returned p.
Effects: Deallocates the storage referenced by p.
Remarks: Uses ​::​operator delete ([new.delete]), but it is unspecified when this function is called.

20.2.9.3 Operators [allocator.globals]

template<class T, class U> constexpr bool operator==(const allocator<T>&, const allocator<U>&) noexcept;
Returns: true.

20.2.10 addressof [specialized.addressof]

template<class T> constexpr T* addressof(T& r) noexcept;
Returns: The actual address of the object or function referenced by r, even in the presence of an overloaded operator&.
Remarks: An expression addressof(E) is a constant subexpression ([defns.const.subexpr]) if E is an lvalue constant subexpression.

20.2.11 C library memory allocation [c.malloc]

[Note 1:
The header <cstdlib> declares the functions described in this subclause.
— end note]
void* aligned_alloc(size_t alignment, size_t size); void* calloc(size_t nmemb, size_t size); void* malloc(size_t size); void* realloc(void* ptr, size_t size);
Effects: These functions have the semantics specified in the C standard library.
Remarks: These functions do not attempt to allocate storage by calling ​::​operator new() ([new.delete]).
These functions implicitly create objects ([intro.object]) in the returned region of storage and return a pointer to a suitable created object.
In the case of calloc and realloc, the objects are created before the storage is zeroed or copied, respectively.
void free(void* ptr);
Effects: This function has the semantics specified in the C standard library.
Remarks: This function does not attempt to deallocate storage by calling ​::​operator delete().
See also: ISO C 7.22.3

20.3 Smart pointers [smartptr]

20.3.1 Unique-ownership pointers [unique.ptr]

20.3.1.1 General [unique.ptr.general]

A unique pointer is an object that owns another object and manages that other object through a pointer.
More precisely, a unique pointer is an object u that stores a pointer to a second object p and will dispose of p when u is itself destroyed (e.g., when leaving block scope ([stmt.dcl])).
In this context, u is said to own p.
The mechanism by which u disposes of p is known as p's associated deleter, a function object whose correct invocation results in p's appropriate disposition (typically its deletion).
Let the notation u.p denote the pointer stored by u, and let u.d denote the associated deleter.
Upon request, u can reset (replace) u.p and u.d with another pointer and deleter, but properly disposes of its owned object via the associated deleter before such replacement is considered completed.
Each object of a type U instantiated from the unique_­ptr template specified in [unique.ptr] has the strict ownership semantics, specified above, of a unique pointer.
In partial satisfaction of these semantics, each such U is Cpp17MoveConstructible and Cpp17MoveAssignable, but is not Cpp17CopyConstructible nor Cpp17CopyAssignable.
The template parameter T of unique_­ptr may be an incomplete type.
[Note 1:
The uses of unique_­ptr include providing exception safety for dynamically allocated memory, passing ownership of dynamically allocated memory to a function, and returning dynamically allocated memory from a function.
— end note]

20.3.1.2 Default deleters [unique.ptr.dltr]

20.3.1.2.1 In general [unique.ptr.dltr.general]

The class template default_­delete serves as the default deleter (destruction policy) for the class template unique_­ptr.
The template parameter T of default_­delete may be an incomplete type.

20.3.1.2.2 default_­delete [unique.ptr.dltr.dflt]

namespace std { template<class T> struct default_delete { constexpr default_delete() noexcept = default; template<class U> constexpr default_delete(const default_delete<U>&) noexcept; constexpr void operator()(T*) const; }; }
template<class U> constexpr default_delete(const default_delete<U>& other) noexcept;
Constraints: U* is implicitly convertible to T*.
Effects: Constructs a default_­delete object from another default_­delete<U> object.
constexpr void operator()(T* ptr) const;
Mandates: T is a complete type.
Effects: Calls delete on ptr.

20.3.1.2.3 default_­delete<T[]> [unique.ptr.dltr.dflt1]

namespace std { template<class T> struct default_delete<T[]> { constexpr default_delete() noexcept = default; template<class U> constexpr default_delete(const default_delete<U[]>&) noexcept; template<class U> constexpr void operator()(U* ptr) const; }; }
template<class U> constexpr default_delete(const default_delete<U[]>& other) noexcept;
Constraints: U(*)[] is convertible to T(*)[].
Effects: Constructs a default_­delete object from another default_­delete<U[]> object.
template<class U> constexpr void operator()(U* ptr) const;
Constraints: U(*)[] is convertible to T(*)[].
Mandates: U is a complete type.
Effects: Calls delete[] on ptr.

20.3.1.3 unique_­ptr for single objects [unique.ptr.single]

20.3.1.3.1 General [unique.ptr.single.general]

namespace std { template<class T, class D = default_delete<T>> class unique_ptr { public: using pointer = see below; using element_type = T; using deleter_type = D; // [unique.ptr.single.ctor], constructors constexpr unique_ptr() noexcept; constexpr explicit unique_ptr(type_identity_t<pointer> p) noexcept; constexpr unique_ptr(type_identity_t<pointer> p, see below d1) noexcept; constexpr unique_ptr(type_identity_t<pointer> p, see below d2) noexcept; constexpr unique_ptr(unique_ptr&& u) noexcept; constexpr unique_ptr(nullptr_t) noexcept; template<class U, class E> constexpr unique_ptr(unique_ptr<U, E>&& u) noexcept; // [unique.ptr.single.dtor], destructor constexpr ~unique_ptr(); // [unique.ptr.single.asgn], assignment constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; template<class U, class E> constexpr unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept; constexpr unique_ptr& operator=(nullptr_t) noexcept; // [unique.ptr.single.observers], observers constexpr add_lvalue_reference_t<T> operator*() const noexcept(see below); constexpr pointer operator->() const noexcept; constexpr pointer get() const noexcept; constexpr deleter_type& get_deleter() noexcept; constexpr const deleter_type& get_deleter() const noexcept; constexpr explicit operator bool() const noexcept; // [unique.ptr.single.modifiers], modifiers constexpr pointer release() noexcept; constexpr void reset(pointer p = pointer()) noexcept; constexpr void swap(unique_ptr& u) noexcept; // disable copy from lvalue unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete; }; }
The default type for the template parameter D is default_­delete.
A client-supplied template argument D shall be a function object type ([function.objects]), lvalue reference to function, or lvalue reference to function object type for which, given a value d of type D and a value ptr of type unique_­ptr<T, D>​::​pointer, the expression d(ptr) is valid and has the effect of disposing of the pointer as appropriate for that deleter.
If the deleter's type D is not a reference type, D shall meet the Cpp17Destructible requirements (Table 36).
If the qualified-id remove_­reference_­t<D>​::​pointer is valid and denotes a type ([temp.deduct]), then unique_­ptr<T, D>​::​pointer shall be a synonym for remove_­reference_­t<D>​::​pointer.
Otherwise unique_­ptr<T, D>​::​pointer shall be a synonym for element_­type*.
The type unique_­ptr<T, D>​::​pointer shall meet the Cpp17NullablePointer requirements (Table 37).
[Example 1:
Given an allocator type X ([allocator.requirements.general]) and letting A be a synonym for allocator_­traits<X>, the types A​::​pointer, A​::​const_­pointer, A​::​void_­pointer, and A​::​const_­void_­pointer may be used as unique_­ptr<T, D>​::​pointer.
— end example]

20.3.1.3.2 Constructors [unique.ptr.single.ctor]

constexpr unique_ptr() noexcept; constexpr unique_ptr(nullptr_t) noexcept;
Constraints: is_­pointer_­v<deleter_­type> is false and is_­default_­constructible_­v<deleter_­type> is true.
Preconditions: D meets the Cpp17DefaultConstructible requirements (Table 31), and that construction does not throw an exception.
Effects: Constructs a unique_­ptr object that owns nothing, value-initializing the stored pointer and the stored deleter.
Postconditions: get() == nullptr.
get_­deleter() returns a reference to the stored deleter.
constexpr explicit unique_ptr(type_identity_t<pointer> p) noexcept;
Constraints: is_­pointer_­v<deleter_­type> is false and is_­default_­constructible_­v<deleter_­type> is true.
Preconditions: D meets the Cpp17DefaultConstructible requirements (Table 31), and that construction does not throw an exception.
Effects: Constructs a unique_­ptr which owns p, initializing the stored pointer with p and value-initializing the stored deleter.
Postconditions: get() == p.
get_­deleter() returns a reference to the stored deleter.
constexpr unique_ptr(type_identity_t<pointer> p, const D& d) noexcept; constexpr unique_ptr(type_identity_t<pointer> p, remove_reference_t<D>&& d) noexcept;
Constraints: is_­constructible_­v<D, decltype(d)> is true.
Preconditions: For the first constructor, if D is not a reference type, D meets the Cpp17CopyConstructible requirements and such construction does not exit via an exception.
For the second constructor, if D is not a reference type, D meets the Cpp17MoveConstructible requirements and such construction does not exit via an exception.
Effects: Constructs a unique_­ptr object which owns p, initializing the stored pointer with p and initializing the deleter from std​::​forward<decltype(d)>(d).
Postconditions: get() == p.
get_­deleter() returns a reference to the stored deleter.
If D is a reference type then get_­deleter() returns a reference to the lvalue d.
Remarks: If D is a reference type, the second constructor is defined as deleted.
[Example 1: D d; unique_ptr<int, D> p1(new int, D()); // D must be Cpp17MoveConstructible unique_ptr<int, D> p2(new int, d); // D must be Cpp17CopyConstructible unique_ptr<int, D&> p3(new int, d); // p3 holds a reference to d unique_ptr<int, const D&> p4(new int, D()); // error: rvalue deleter object combined // with reference deleter type — end example]
constexpr unique_ptr(unique_ptr&& u) noexcept;
Constraints: is_­move_­constructible_­v<D> is true.
Preconditions: If D is not a reference type, D meets the Cpp17MoveConstructible requirements (Table 32).
Construction of the deleter from an rvalue of type D does not throw an exception.
Effects: Constructs a unique_­ptr from u.
If D is a reference type, this deleter is copy constructed from u's deleter; otherwise, this deleter is move constructed from u's deleter.
[Note 1:
The construction of the deleter can be implemented with std​::​forward<D>.
— end note]
Postconditions: get() yields the value u.get() yielded before the construction.
u.get() == nullptr.
get_­deleter() returns a reference to the stored deleter that was constructed from u.get_­deleter().
If D is a reference type then get_­deleter() and u.get_­deleter() both reference the same lvalue deleter.
template<class U, class E> constexpr unique_ptr(unique_ptr<U, E>&& u) noexcept;
Constraints:
  • unique_­ptr<U, E>​::​pointer is implicitly convertible to pointer,
  • U is not an array type, and
  • either D is a reference type and E is the same type as D, or D is not a reference type and E is implicitly convertible to D.
Preconditions: If E is not a reference type, construction of the deleter from an rvalue of type E is well-formed and does not throw an exception.
Otherwise, E is a reference type and construction of the deleter from an lvalue of type E is well-formed and does not throw an exception.
Effects: Constructs a unique_­ptr from u.
If E is a reference type, this deleter is copy constructed from u's deleter; otherwise, this deleter is move constructed from u's deleter.
[Note 2:
The deleter constructor can be implemented with std​::​forward<E>.
— end note]
Postconditions: get() yields the value u.get() yielded before the construction.
u.get() == nullptr.
get_­deleter() returns a reference to the stored deleter that was constructed from u.get_­deleter().

20.3.1.3.3 Destructor [unique.ptr.single.dtor]

constexpr ~unique_ptr();
Effects: Equivalent to: if (get()) get_­deleter()(get());
[Note 1:
The use of default_­delete requires T to be a complete type.
— end note]
Remarks: The behavior is undefined if the evaluation of get_­deleter()(get()) throws an exception.

20.3.1.3.4 Assignment [unique.ptr.single.asgn]

constexpr unique_ptr& operator=(unique_ptr&& u) noexcept;
Constraints: is_­move_­assignable_­v<D> is true.
Preconditions: If D is not a reference type, D meets the Cpp17MoveAssignable requirements (Table 34) and assignment of the deleter from an rvalue of type D does not throw an exception.
Otherwise, D is a reference type; remove_­reference_­t<D> meets the Cpp17CopyAssignable requirements and assignment of the deleter from an lvalue of type D does not throw an exception.
Effects: Calls reset(u.release()) followed by get_­deleter() = std​::​forward<D>(u.get_­deleter()).
Postconditions: If this != addressof(u), u.get() == nullptr, otherwise u.get() is unchanged.
Returns: *this.
template<class U, class E> constexpr unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
Constraints:
  • unique_­ptr<U, E>​::​pointer is implicitly convertible to pointer, and
  • U is not an array type, and
  • is_­assignable_­v<D&, E&&> is true.
Preconditions: If E is not a reference type, assignment of the deleter from an rvalue of type E is well-formed and does not throw an exception.
Otherwise, E is a reference type and assignment of the deleter from an lvalue of type E is well-formed and does not throw an exception.
Effects: Calls reset(u.release()) followed by get_­deleter() = std​::​forward<E>(u.get_­deleter()).
Postconditions: u.get() == nullptr.
Returns: *this.
constexpr unique_ptr& operator=(nullptr_t) noexcept;
Effects: As if by reset().
Postconditions: get() == nullptr.
Returns: *this.

20.3.1.3.5 Observers [unique.ptr.single.observers]

constexpr add_lvalue_reference_t<T> operator*() const noexcept(noexcept(*declval<pointer>()));
Preconditions: get() != nullptr.
Returns: *get().
constexpr pointer operator->() const noexcept;
Preconditions: get() != nullptr.
Returns: get().
[Note 1:
The use of this function typically requires that T be a complete type.
— end note]
constexpr pointer get() const noexcept;
Returns: The stored pointer.
constexpr deleter_type& get_deleter() noexcept; constexpr const deleter_type& get_deleter() const noexcept;
Returns: A reference to the stored deleter.
constexpr explicit operator bool() const noexcept;
Returns: get() != nullptr.

20.3.1.3.6 Modifiers [unique.ptr.single.modifiers]

constexpr pointer release() noexcept;
Postconditions: get() == nullptr.
Returns: The value get() had at the start of the call to release.
constexpr void reset(pointer p = pointer()) noexcept;
Effects: Assigns p to the stored pointer, and then, with the old value of the stored pointer, old_­p, evaluates if (old_­p) get_­deleter()(old_­p);
[Note 1:
The order of these operations is significant because the call to get_­deleter() might destroy *this.
— end note]
Postconditions: get() == p.
[Note 2:
The postcondition does not hold if the call to get_­deleter() destroys *this since this->get() is no longer a valid expression.
— end note]
Remarks: The behavior is undefined if the evaluation of get_­deleter()(old_­p) throws an exception.
constexpr void swap(unique_ptr& u) noexcept;
Preconditions: get_­deleter() is swappable ([swappable.requirements]) and does not throw an exception under swap.
Effects: Invokes swap on the stored pointers and on the stored deleters of *this and u.

20.3.1.4 unique_­ptr for array objects with a runtime length [unique.ptr.runtime]

20.3.1.4.1 General [unique.ptr.runtime.general]

namespace std { template<class T, class D> class unique_ptr<T[], D> { public: using pointer = see below; using element_type = T; using deleter_type = D; // [unique.ptr.runtime.ctor], constructors constexpr unique_ptr() noexcept; template<class U> constexpr explicit unique_ptr(U p) noexcept; template<class U> constexpr unique_ptr(U p, see below d) noexcept; template<class U> constexpr unique_ptr(U p, see below d) noexcept; constexpr unique_ptr(unique_ptr&& u) noexcept; template<class U, class E> constexpr unique_ptr(unique_ptr<U, E>&& u) noexcept; constexpr unique_ptr(nullptr_t) noexcept; // destructor constexpr ~unique_ptr(); // assignment constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; template<class U, class E> constexpr unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept; constexpr unique_ptr& operator=(nullptr_t) noexcept; // [unique.ptr.runtime.observers], observers constexpr T& operator[](size_t i) const; constexpr pointer get() const noexcept; constexpr deleter_type& get_deleter() noexcept; constexpr const deleter_type& get_deleter() const noexcept; constexpr explicit operator bool() const noexcept; // [unique.ptr.runtime.modifiers], modifiers constexpr pointer release() noexcept; template<class U> constexpr void reset(U p) noexcept; constexpr void reset(nullptr_t = nullptr) noexcept; constexpr void swap(unique_ptr& u) noexcept; // disable copy from lvalue unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete; }; }
A specialization for array types is provided with a slightly altered interface.
  • Conversions between different types of unique_­ptr<T[], D> that would be disallowed for the corresponding pointer-to-array types, and conversions to or from the non-array forms of unique_­ptr, produce an ill-formed program.
  • Pointers to types derived from T are rejected by the constructors, and by reset.
  • The observers operator* and operator-> are not provided.
  • The indexing observer operator[] is provided.
  • The default deleter will call delete[].
Descriptions are provided below only for members that differ from the primary template.
The template argument T shall be a complete type.

20.3.1.4.2 Constructors [unique.ptr.runtime.ctor]

template<class U> constexpr explicit unique_ptr(U p) noexcept;
This constructor behaves the same as the constructor in the primary template that takes a single parameter of type pointer.
Constraints:
  • U is the same type as pointer, or
  • pointer is the same type as element_­type*, U is a pointer type V*, and V(*)[] is convertible to element_­type(*)[].
template<class U> constexpr unique_ptr(U p, see below d) noexcept; template<class U> constexpr unique_ptr(U p, see below d) noexcept;
These constructors behave the same as the constructors in the primary template that take a parameter of type pointer and a second parameter.
Constraints:
  • U is the same type as pointer,
  • U is nullptr_­t, or
  • pointer is the same type as element_­type*, U is a pointer type V*, and V(*)[] is convertible to element_­type(*)[].
template<class U, class E> constexpr unique_ptr(unique_ptr<U, E>&& u) noexcept;
This constructor behaves the same as in the primary template.
Constraints: Where UP is unique_­ptr<U, E>:
  • U is an array type, and
  • pointer is the same type as element_­type*, and
  • UP​::​pointer is the same type as UP​::​element_­type*, and
  • UP​::​element_­type(*)[] is convertible to element_­type(*)[], and
  • either D is a reference type and E is the same type as D, or D is not a reference type and E is implicitly convertible to D.
[Note 1:
This replaces the Constraints: specification of the primary template.
— end note]

20.3.1.4.3 Assignment [unique.ptr.runtime.asgn]

template<class U, class E> constexpr unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
This operator behaves the same as in the primary template.
Constraints: Where UP is unique_­ptr<U, E>:
  • U is an array type, and
  • pointer is the same type as element_­type*, and
  • UP​::​pointer is the same type as UP​::​element_­type*, and
  • UP​::​element_­type(*)[] is convertible to element_­type(*)[], and
  • is_­assignable_­v<D&, E&&> is true.
[Note 1:
This replaces the Constraints: specification of the primary template.
— end note]

20.3.1.4.4 Observers [unique.ptr.runtime.observers]

constexpr T& operator[](size_t i) const;
Preconditions: the number of elements in the array to which the stored pointer points.
Returns: get()[i].

20.3.1.4.5 Modifiers [unique.ptr.runtime.modifiers]

constexpr void reset(nullptr_t p = nullptr) noexcept;
Effects: Equivalent to reset(pointer()).
constexpr template<class U> void reset(U p) noexcept;
This function behaves the same as the reset member of the primary template.
Constraints:
  • U is the same type as pointer, or
  • pointer is the same type as element_­type*, U is a pointer type V*, and V(*)[] is convertible to element_­type(*)[].

20.3.1.5 Creation [unique.ptr.create]

template<class T, class... Args> constexpr unique_ptr<T> make_unique(Args&&... args);
Constraints: T is not an array type.
Returns: unique_­ptr<T>(new T(std​::​forward<Args>(args)...)).
template<class T> constexpr unique_ptr<T> make_unique(size_t n);
Constraints: T is an array of unknown bound.
Returns: unique_­ptr<T>(new remove_­extent_­t<T>[n]()).
template<class T, class... Args> unspecified make_unique(Args&&...) = delete;
Constraints: T is an array of known bound.
template<class T> constexpr unique_ptr<T> make_unique_for_overwrite();
Constraints: T is not an array type.
Returns: unique_­ptr<T>(new T).
template<class T> constexpr unique_ptr<T> make_unique_for_overwrite(size_t n);
Constraints: T is an array of unknown bound.
Returns: unique_­ptr<T>(new remove_­extent_­t<T>[n]).
template<class T, class... Args> unspecified make_unique_for_overwrite(Args&&...) = delete;
Constraints: T is an array of known bound.

20.3.1.6 Specialized algorithms [unique.ptr.special]

template<class T, class D> constexpr void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) noexcept;
Constraints: is_­swappable_­v<D> is true.
Effects: Calls x.swap(y).
template<class T1, class D1, class T2, class D2> constexpr bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
Returns: x.get() == y.get().
template<class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
Let CT denote common_type_t<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer>
Mandates:
  • unique_­ptr<T1, D1>​::​pointer is implicitly convertible to CT and
  • unique_­ptr<T2, D2>​::​pointer is implicitly convertible to CT.
Preconditions: The specialization less<CT> is a function object type ([function.objects]) that induces a strict weak ordering ([alg.sorting]) on the pointer values.
Returns: less<CT>()(x.get(), y.get()).
template<class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
Returns: y < x.
template<class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
Returns: !(y < x).
template<class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
Returns: !(x < y).
template<class T1, class D1, class T2, class D2> requires three_­way_­comparable_­with<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer> compare_three_way_result_t<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer> operator<=>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
Returns: compare_­three_­way()(x.get(), y.get()).
template<class T, class D> constexpr bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept;
Returns: !x.
template<class T, class D> constexpr bool operator<(const unique_ptr<T, D>& x, nullptr_t); template<class T, class D> constexpr bool operator<(nullptr_t, const unique_ptr<T, D>& x);
Preconditions: The specialization less<unique_­ptr<T, D>​::​pointer> is a function object type ([function.objects]) that induces a strict weak ordering ([alg.sorting]) on the pointer values.
Returns: The first function template returns less<unique_ptr<T, D>::pointer>()(x.get(), nullptr)
The second function template returns less<unique_ptr<T, D>::pointer>()(nullptr, x.get())
template<class T, class D> constexpr bool operator>(const unique_ptr<T, D>& x, nullptr_t); template<class T, class D> constexpr bool operator>(nullptr_t, const unique_ptr<T, D>& x);
Returns: The first function template returns nullptr < x.
The second function template returns x < nullptr.
template<class T, class D> constexpr bool operator<=(const unique_ptr<T, D>& x, nullptr_t); template<class T, class D> constexpr bool operator<=(nullptr_t, const unique_ptr<T, D>& x);
Returns: The first function template returns !(nullptr < x).
The second function template returns !(x < nullptr).
template<class T, class D> constexpr bool operator>=(const unique_ptr<T, D>& x, nullptr_t); template<class T, class D> constexpr bool operator>=(nullptr_t, const unique_ptr<T, D>& x);
Returns: The first function template returns !(x < nullptr).
The second function template returns !(nullptr < x).
template<class T, class D> requires three_­way_­comparable<typename unique_ptr<T, D>::pointer> constexpr compare_three_way_result_t<typename unique_ptr<T, D>::pointer> operator<=>(const unique_ptr<T, D>& x, nullptr_t);
Returns: compare_three_way()(x.get(), static_cast<typename unique_ptr<T, D>::pointer>(nullptr)).

20.3.1.7 I/O [unique.ptr.io]

template<class E, class T, class Y, class D> basic_ostream<E, T>& operator<<(basic_ostream<E, T>& os, const unique_ptr<Y, D>& p);
Constraints: os << p.get() is a valid expression.
Effects: Equivalent to: os << p.get();
Returns: os.

20.3.2 Shared-ownership pointers [util.sharedptr]

20.3.2.1 Class bad_­weak_­ptr [util.smartptr.weak.bad]

namespace std { class bad_weak_ptr : public exception { public: // see [exception] for the specification of the special member functions const char* what() const noexcept override; }; }
An exception of type bad_­weak_­ptr is thrown by the shared_­ptr constructor taking a weak_­ptr.
const char* what() const noexcept override;
Returns: An implementation-defined ntbs.

20.3.2.2 Class template shared_­ptr [util.smartptr.shared]

20.3.2.2.1 General [util.smartptr.shared.general]

The shared_­ptr class template stores a pointer, usually obtained via new.
shared_­ptr implements semantics of shared ownership; the last remaining owner of the pointer is responsible for destroying the object, or otherwise releasing the resources associated with the stored pointer.
A shared_­ptr is said to be empty if it does not own a pointer.
namespace std { template<class T> class shared_ptr { public: using element_type = remove_extent_t<T>; using weak_type = weak_ptr<T>; // [util.smartptr.shared.const], constructors constexpr shared_ptr() noexcept; constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { } template<class Y> explicit shared_ptr(Y* p); template<class Y, class D> shared_ptr(Y* p, D d); template<class Y, class D, class A> shared_ptr(Y* p, D d, A a); template<class D> shared_ptr(nullptr_t p, D d); template<class D, class A> shared_ptr(nullptr_t p, D d, A a); template<class Y> shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept; template<class Y> shared_ptr(shared_ptr<Y>&& r, element_type* p) noexcept; shared_ptr(const shared_ptr& r) noexcept; template<class Y> shared_ptr(const shared_ptr<Y>& r) noexcept; shared_ptr(shared_ptr&& r) noexcept; template<class Y> shared_ptr(shared_ptr<Y>&& r) noexcept; template<class Y> explicit shared_ptr(const weak_ptr<Y>& r); template<class Y, class D> shared_ptr(unique_ptr<Y, D>&& r); // [util.smartptr.shared.dest], destructor ~shared_ptr(); // [util.smartptr.shared.assign], assignment shared_ptr& operator=(const shared_ptr& r) noexcept; template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) noexcept; shared_ptr& operator=(shared_ptr&& r) noexcept; template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r) noexcept; template<class Y, class D> shared_ptr& operator=(unique_ptr<Y, D>&& r); // [util.smartptr.shared.mod], modifiers void swap(shared_ptr& r) noexcept; void reset() noexcept; template<class Y> void reset(Y* p); template<class Y, class D> void reset(Y* p, D d); template<class Y, class D, class A> void reset(Y* p, D d, A a); // [util.smartptr.shared.obs], observers element_type* get() const noexcept; T& operator*() const noexcept; T* operator->() const noexcept; element_type& operator[](ptrdiff_t i) const; long use_count() const noexcept; explicit operator bool() const noexcept; template<class U> bool owner_before(const shared_ptr<U>& b) const noexcept; template<class U> bool owner_before(const weak_ptr<U>& b) const noexcept; }; template<class T> shared_ptr(weak_ptr<T>) -> shared_ptr<T>; template<class T, class D> shared_ptr(unique_ptr<T, D>) -> shared_ptr<T>; }
Specializations of shared_­ptr shall be Cpp17CopyConstructible, Cpp17CopyAssignable, and Cpp17LessThanComparable, allowing their use in standard containers.
Specializations of shared_­ptr shall be contextually convertible to bool, allowing their use in boolean expressions and declarations in conditions.
The template parameter T of shared_­ptr may be an incomplete type.
[Note 1:
T can be a function type.
— end note]
[Example 1: if (shared_ptr<X> px = dynamic_pointer_cast<X>(py)) { // do something with px } — end example]
For purposes of determining the presence of a data race, member functions shall access and modify only the shared_­ptr and weak_­ptr objects themselves and not objects they refer to.
Changes in use_­count() do not reflect modifications that can introduce data races.
For the purposes of subclause [smartptr], a pointer type Y* is said to be compatible with a pointer type T* when either Y* is convertible to T* or Y is U[N] and T is cv U[].

20.3.2.2.2 Constructors [util.smartptr.shared.const]

In the constructor definitions below, enables shared_­from_­this with p, for a pointer p of type Y*, means that if Y has an unambiguous and accessible base class that is a specialization of enable_­shared_­from_­this ([util.smartptr.enab]), then remove_­cv_­t<Y>* shall be implicitly convertible to T* and the constructor evaluates the statement: if (p != nullptr && p->weak_this.expired()) p->weak_this = shared_ptr<remove_cv_t<Y>>(*this, const_cast<remove_cv_t<Y>*>(p));
The assignment to the weak_­this member is not atomic and conflicts with any potentially concurrent access to the same object ([intro.multithread]).
constexpr shared_ptr() noexcept;
Postconditions: use_­count() == 0 && get() == nullptr.
template<class Y> explicit shared_ptr(Y* p);
Constraints: When T is an array type, the expression delete[] p is well-formed and either T is U[N] and Y(*)[N] is convertible to T*, or T is U[] and Y(*)[] is convertible to T*.
When T is not an array type, the expression delete p is well-formed and Y* is convertible to T*.
Mandates: Y is a complete type.
Preconditions: The expression delete[] p, when T is an array type, or delete p, when T is not an array type, has well-defined behavior, and does not throw exceptions.
Effects: When T is not an array type, constructs a shared_­ptr object that owns the pointer p.
Otherwise, constructs a shared_­ptr that owns p and a deleter of an unspecified type that calls delete[] p.
When T is not an array type, enables shared_­from_­this with p.
If an exception is thrown, delete p is called when T is not an array type, delete[] p otherwise.
Postconditions: use_­count() == 1 && get() == p.
Throws: bad_­alloc, or an implementation-defined exception when a resource other than memory cannot be obtained.
template<class Y, class D> shared_ptr(Y* p, D d); template<class Y, class D, class A> shared_ptr(Y* p, D d, A a); template<class D> shared_ptr(nullptr_t p, D d); template<class D, class A> shared_ptr(nullptr_t p, D d, A a);
Constraints: is_­move_­constructible_­v<D> is true, and d(p) is a well-formed expression.
For the first two overloads:
  • If T is an array type, then either T is U[N] and Y(*)[N] is convertible to T*, or T is U[] and Y(*)[] is convertible to T*.
  • If T is not an array type, then Y* is convertible to T*.
Preconditions: Construction of d and a deleter of type D initialized with std​::​move(d) do not throw exceptions.
The expression d(p) has well-defined behavior and does not throw exceptions.
A meets the Cpp17Allocator requirements ([allocator.requirements.general]).
Effects: Constructs a shared_­ptr object that owns the object p and the deleter d.
When T is not an array type, the first and second constructors enable shared_­from_­this with p.
The second and fourth constructors shall use a copy of a to allocate memory for internal use.
If an exception is thrown, d(p) is called.
Postconditions: use_­count() == 1 && get() == p.
Throws: bad_­alloc, or an implementation-defined exception when a resource other than memory cannot be obtained.
template<class Y> shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept; template<class Y> shared_ptr(shared_ptr<Y>&& r, element_type* p) noexcept;
Effects: Constructs a shared_­ptr instance that stores p and shares ownership with the initial value of r.
Postconditions: get() == p.
For the second overload, r is empty and r.get() == nullptr.
[Note 1:
Use of this constructor leads to a dangling pointer unless p remains valid at least until the ownership group of r is destroyed.
— end note]
[Note 2:
This constructor allows creation of an empty shared_­ptr instance with a non-null stored pointer.
— end note]
shared_ptr(const shared_ptr& r) noexcept; template<class Y> shared_ptr(const shared_ptr<Y>& r) noexcept;
Constraints: For the second constructor, Y* is compatible with T*.
Effects: If r is empty, constructs an empty shared_­ptr object; otherwise, constructs a shared_­ptr object that shares ownership with r.
Postconditions: get() == r.get() && use_­count() == r.use_­count().
shared_ptr(shared_ptr&& r) noexcept; template<class Y> shared_ptr(shared_ptr<Y>&& r) noexcept;
Constraints: For the second constructor, Y* is compatible with T*.
Effects: Move constructs a shared_­ptr instance from r.
Postconditions: *this contains the old value of r.
r is empty, and r.get() == nullptr.
template<class Y> explicit shared_ptr(const weak_ptr<Y>& r);
Constraints: Y* is compatible with T*.
Effects: Constructs a shared_­ptr object that shares ownership with r and stores a copy of the pointer stored in r.
If an exception is thrown, the constructor has no effect.
Postconditions: use_­count() == r.use_­count().
Throws: bad_­weak_­ptr when r.expired().
template<class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
Constraints: Y* is compatible with T* and unique_­ptr<Y, D>​::​pointer is convertible to element_­type*.
Effects: If r.get() == nullptr, equivalent to shared_­ptr().
Otherwise, if D is not a reference type, equivalent to shared_­ptr(r.release(), std​::​move(r.get_­deleter())).
Otherwise, equivalent to shared_­ptr(r.release(), ref(r.get_­deleter())).
If an exception is thrown, the constructor has no effect.

20.3.2.2.3 Destructor [util.smartptr.shared.dest]

~shared_ptr();
Effects:
  • If *this is empty or shares ownership with another shared_­ptr instance (use_­count() > 1), there are no side effects.
  • Otherwise, if *this owns an object p and a deleter d, d(p) is called.
  • Otherwise, *this owns a pointer p, and delete p is called.
[Note 1:
Since the destruction of *this decreases the number of instances that share ownership with *this by one, after *this has been destroyed all shared_­ptr instances that shared ownership with *this will report a use_­count() that is one less than its previous value.
— end note]

20.3.2.2.4 Assignment [util.smartptr.shared.assign]

shared_ptr& operator=(const shared_ptr& r) noexcept; template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) noexcept;
Effects: Equivalent to shared_­ptr(r).swap(*this).
Returns: *this.
[Note 1:
The use count updates caused by the temporary object construction and destruction are not observable side effects, so the implementation can meet the effects (and the implied guarantees) via different means, without creating a temporary.
In particular, in the example: shared_ptr<int> p(new int); shared_ptr<void> q(p); p = p; q = p; both assignments can be no-ops.
— end note]
shared_ptr& operator=(shared_ptr&& r) noexcept; template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r) noexcept;
Effects: Equivalent to shared_­ptr(std​::​move(r)).swap(*this).
Returns: *this.
template<class Y, class D> shared_ptr& operator=(unique_ptr<Y, D>&& r);
Effects: Equivalent to shared_­ptr(std​::​move(r)).swap(*this).
Returns: *this.

20.3.2.2.5 Modifiers [util.smartptr.shared.mod]

void swap(shared_ptr& r) noexcept;
Effects: Exchanges the contents of *this and r.
void reset() noexcept;
Effects: Equivalent to shared_­ptr().swap(*this).
template<class Y> void reset(Y* p);
Effects: Equivalent to shared_­ptr(p).swap(*this).
template<class Y, class D> void reset(Y* p, D d);
Effects: Equivalent to shared_­ptr(p, d).swap(*this).
template<class Y, class D, class A> void reset(Y* p, D d, A a);
Effects: Equivalent to shared_­ptr(p, d, a).swap(*this).

20.3.2.2.6 Observers [util.smartptr.shared.obs]

element_type* get() const noexcept;
Returns: The stored pointer.
T& operator*() const noexcept;
Preconditions: get() != 0.
Returns: *get().
Remarks: When T is an array type or cv void, it is unspecified whether this member function is declared.
If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well-formed.
T* operator->() const noexcept;
Preconditions: get() != 0.
Returns: get().
Remarks: When T is an array type, it is unspecified whether this member function is declared.
If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well-formed.
element_type& operator[](ptrdiff_t i) const;
Preconditions: get() != 0 && i >= 0.
If T is U[N], i < N.
Returns: get()[i].
Throws: Nothing.
Remarks: When T is not an array type, it is unspecified whether this member function is declared.
If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well-formed.
long use_count() const noexcept;
Synchronization: None.
Returns: The number of shared_­ptr objects, *this included, that share ownership with *this, or 0 when *this is empty.
[Note 1:
get() == nullptr does not imply a specific return value of use_­count().
— end note]
[Note 2:
weak_­ptr<T>​::​lock() can affect the return value of use_­count().
— end note]
[Note 3:
When multiple threads might affect the return value of use_­count(), the result is approximate.
In particular, use_­count() == 1 does not imply that accesses through a previously destroyed shared_­ptr have in any sense completed.
— end note]
explicit operator bool() const noexcept;
Returns: get() != 0.
template<class U> bool owner_before(const shared_ptr<U>& b) const noexcept; template<class U> bool owner_before(const weak_ptr<U>& b) const noexcept;
Returns: An unspecified value such that
  • x.owner_­before(y) defines a strict weak ordering as defined in [alg.sorting];
  • under the equivalence relation defined by owner_­before, !a.owner_­before(b) && !b.owner_­before(a), two shared_­ptr or weak_­ptr instances are equivalent if and only if they share ownership or are both empty.

20.3.2.2.7 Creation [util.smartptr.shared.create]

The common requirements that apply to all make_­shared, allocate_­shared, make_­shared_­for_­overwrite, and allocate_­shared_­for_­overwrite overloads, unless specified otherwise, are described below.
template<class T, ...> shared_ptr<T> make_shared(args); template<class T, class A, ...> shared_ptr<T> allocate_shared(const A& a, args); template<class T, ...> shared_ptr<T> make_shared_for_overwrite(args); template<class T, class A, ...> shared_ptr<T> allocate_shared_for_overwrite(const A& a, args);
Preconditions: A meets the Cpp17Allocator requirements ([allocator.requirements.general]).
Effects: Allocates memory for an object of type T (or U[N] when T is U[], where N is determined from args as specified by the concrete overload).
The object is initialized from args as specified by the concrete overload.
The allocate_­shared and allocate_­shared_­for_­overwrite templates use a copy of a (rebound for an unspecified value_­type) to allocate memory.
If an exception is thrown, the functions have no effect.
Postconditions: r.get() != 0 && r.use_­count() == 1, where r is the return value.
Returns: A shared_­ptr instance that stores and owns the address of the newly constructed object.
Throws: bad_­alloc, or an exception thrown from allocate or from the initialization of the object.
Remarks:
  • Implementations should perform no more than one memory allocation.
    [Note 1:
    This provides efficiency equivalent to an intrusive smart pointer.
    — end note]
  • When an object of an array type U is specified to have an initial value of u (of the same type), this shall be interpreted to mean that each array element of the object has as its initial value the corresponding element from u.
  • When an object of an array type is specified to have a default initial value, this shall be interpreted to mean that each array element of the object has a default initial value.
  • When a (sub)object of a non-array type U is specified to have an initial value of v, or U(l...), where l... is a list of constructor arguments, make_­shared shall initialize this (sub)object via the expression ​::​new(pv) U(v) or ​::​new(pv) U(l...) respectively, where pv has type void* and points to storage suitable to hold an object of type U.
  • When a (sub)object of a non-array type U is specified to have an initial value of v, or U(l...), where l... is a list of constructor arguments, allocate_­shared shall initialize this (sub)object via the expression
    • allocator_­traits<A2>​::​construct(a2, pv, v) or
    • allocator_­traits<A2>​::​construct(a2, pv, l...)
    respectively, where pv points to storage suitable to hold an object of type U and a2 of type A2 is a rebound copy of the allocator a passed to allocate_­shared such that its value_­type is remove_­cv_­t<U>.
  • When a (sub)object of non-array type U is specified to have a default initial value, make_­shared shall initialize this (sub)object via the expression ​::​new(pv) U(), where pv has type void* and points to storage suitable to hold an object of type U.
  • When a (sub)object of non-array type U is specified to have a default initial value, allocate_­shared shall initialize this (sub)object via the expression allocator_­traits<A2>​::​construct(a2, pv), where pv points to storage suitable to hold an object of type U and a2 of type A2 is a rebound copy of the allocator a passed to allocate_­shared such that its value_­type is remove_­cv_­t<U>.
  • When a (sub)object of non-array type U is initialized by make_­shared_­for_­overwrite or
    allocate_­shared_­for_­overwrite, it is initialized via the expression ​::​new(pv) U, where pv has type void* and points to storage suitable to hold an object of type U.
  • Array elements are initialized in ascending order of their addresses.
  • When the lifetime of the object managed by the return value ends, or when the initialization of an array element throws an exception, the initialized elements are destroyed in the reverse order of their original construction.
  • When a (sub)object of non-array type U that was initialized by make_­shared is to be destroyed, it is destroyed via the expression pv->~U() where pv points to that object of type U.
  • When a (sub)object of non-array type U that was initialized by allocate_­shared is to be destroyed, it is destroyed via the expression allocator_­traits<A2>​::​destroy(a2, pv) where pv points to that object of type remove_­cv_­t<U> and a2 of type A2 is a rebound copy of the allocator a passed to allocate_­shared such that its value_­type is remove_­cv_­t<U>.
[Note 2:
These functions will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as reference counts.
— end note]
template<class T, class... Args> shared_ptr<T> make_shared(Args&&... args); // T is not array template<class T, class A, class... Args> shared_ptr<T> allocate_shared(const A& a, Args&&... args); // T is not array
Constraints: T is not an array type.
Returns: A shared_­ptr to an object of type T with an initial value T(forward<Args>(args)...).
Remarks: The shared_­ptr constructors called by these functions enable shared_­from_­this with the address of the newly constructed object of type T.
[Example 1: shared_ptr<int> p = make_shared<int>(); // shared_­ptr to int() shared_ptr<vector<int>> q = make_shared<vector<int>>(16, 1); // shared_­ptr to vector of 16 elements with value 1 — end example]
template<class T> shared_ptr<T> make_shared(size_t N); // T is U[] template<class T, class A> shared_ptr<T> allocate_shared(const A& a, size_t N); // T is U[]
Constraints: T is of the form U[].
Returns: A shared_­ptr to an object of type U[N] with a default initial value, where U is remove_­extent_­t<T>.
[Example 2: shared_ptr<double[]> p = make_shared<double[]>(1024); // shared_­ptr to a value-initialized double[1024] shared_ptr<double[][2][2]> q = make_shared<double[][2][2]>(6); // shared_­ptr to a value-initialized double[6][2][2] — end example]
template<class T> shared_ptr<T> make_shared(); // T is U[N] template<class T, class A> shared_ptr<T> allocate_shared(const A& a); // T is U[N]
Constraints: T is of the form U[N].
Returns: A shared_­ptr to an object of type T with a default initial value.
[Example 3: shared_ptr<double[1024]> p = make_shared<double[1024]>(); // shared_­ptr to a value-initialized double[1024] shared_ptr<double[6][2][2]> q = make_shared<double[6][2][2]>(); // shared_­ptr to a value-initialized double[6][2][2] — end example]
template<class T> shared_ptr<T> make_shared(size_t N, const remove_extent_t<T>& u); // T is U[] template<class T, class A> shared_ptr<T> allocate_shared(const A& a, size_t N, const remove_extent_t<T>& u); // T is U[]
Constraints: T is of the form U[].
Returns: A shared_­ptr to an object of type U[N], where U is remove_­extent_­t<T> and each array element has an initial value of u.
[Example 4: shared_ptr<double[]> p = make_shared<double[]>(1024, 1.0); // shared_­ptr to a double[1024], where each element is 1.0 shared_ptr<double[][2]> q = make_shared<double[][2]>(6, {1.0, 0.0}); // shared_­ptr to a double[6][2], where each double[2] element is {1.0, 0.0} shared_ptr<vector<int>[]> r = make_shared<vector<int>[]>(4, {1, 2}); // shared_­ptr to a vector<int>[4], where each vector has contents {1, 2} — end example]
template<class T> shared_ptr<T> make_shared(const remove_extent_t<T>& u); // T is U[N] template<class T, class A> shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& u); // T is U[N]
Constraints: T is of the form U[N].
Returns: A shared_­ptr to an object of type T, where each array element of type remove_­extent_­t<T> has an initial value of u.
[Example 5: shared_ptr<double[1024]> p = make_shared<double[1024]>(1.0); // shared_­ptr to a double[1024], where each element is 1.0 shared_ptr<double[6][2]> q = make_shared<double[6][2]>({1.0, 0.0}); // shared_­ptr to a double[6][2], where each double[2] element is {1.0, 0.0} shared_ptr<vector<int>[4]> r = make_shared<vector<int>[4]>({1, 2}); // shared_­ptr to a vector<int>[4], where each vector has contents {1, 2} — end example]
template<class T> shared_ptr<T> make_shared_for_overwrite(); template<class T, class A> shared_ptr<T> allocate_shared_for_overwrite(const A& a);
Constraints: T is not an array of unknown bound.
Returns: A shared_­ptr to an object of type T.
[Example 6: struct X { double data[1024]; }; shared_ptr<X> p = make_shared_for_overwrite<X>(); // shared_­ptr to a default-initialized X, where each element in X​::​data has an indeterminate value shared_ptr<double[1024]> q = make_shared_for_overwrite<double[1024]>(); // shared_­ptr to a default-initialized double[1024], where each element has an indeterminate value — end example]
template<class T> shared_ptr<T> make_shared_for_overwrite(size_t N); template<class T, class A> shared_ptr<T> allocate_shared_for_overwrite(const A& a, size_t N);
Constraints: T is an array of unknown bound.
Returns: A shared_­ptr to an object of type U[N], where U is remove_­extent_­t<T>.
[Example 7: shared_ptr<double[]> p = make_shared_for_overwrite<double[]>(1024); // shared_­ptr to a default-initialized double[1024], where each element has an indeterminate value — end example]

20.3.2.2.8 Comparison [util.smartptr.shared.cmp]

template<class T, class U> bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
Returns: a.get() == b.get().
template<class T> bool operator==(const shared_ptr<T>& a, nullptr_t) noexcept;
Returns: !a.
template<class T, class U> strong_ordering operator<=>(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
Returns: compare_­three_­way()(a.get(), b.get()).
[Note 1:
Defining a comparison operator function allows shared_­ptr objects to be used as keys in associative containers.
— end note]
template<class T> strong_ordering operator<=>(const shared_ptr<T>& a, nullptr_t) noexcept;
Returns: compare_three_way()(a.get(), static_cast<typename shared_ptr<T>::element_type*>(nullptr).

20.3.2.2.9 Specialized algorithms [util.smartptr.shared.spec]

template<class T> void swap(shared_ptr<T>& a, shared_ptr<T>& b) noexcept;
Effects: Equivalent to a.swap(b).

20.3.2.2.10 Casts [util.smartptr.shared.cast]

template<class T, class U> shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U>&& r) noexcept;
Mandates: The expression static_­cast<T*>((U*)nullptr) is well-formed.
Returns: shared_ptr<T>(R, static_cast<typename shared_ptr<T>::element_type*>(r.get())) where R is r for the first overload, and std​::​move(r) for the second.
[Note 1:
The seemingly equivalent expression shared_­ptr<T>(static_­cast<T*>(r.get())) will eventually result in undefined behavior, attempting to delete the same object twice.
— end note]
template<class T, class U> shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> dynamic_pointer_cast(shared_ptr<U>&& r) noexcept;
Mandates: The expression dynamic_­cast<T*>((U*)nullptr) is well-formed.
The expression dynamic_­cast<typename shared_­ptr<T>​::​element_­type*>(r.get()) is well-formed.
Preconditions: The expression dynamic_­cast<typename shared_­ptr<T>​::​element_­type*>(r.get()) has well-defined behavior.
Returns:
  • When dynamic_­cast<typename shared_­ptr<T>​::​element_­type*>(r.get()) returns a non-null value p, shared_­ptr<T>(R, p), where R is r for the first overload, and std​::​move(r) for the second.
  • Otherwise, shared_­ptr<T>().
[Note 2:
The seemingly equivalent expression shared_­ptr<T>(dynamic_­cast<T*>(r.get())) will eventually result in undefined behavior, attempting to delete the same object twice.
— end note]
template<class T, class U> shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> const_pointer_cast(shared_ptr<U>&& r) noexcept;
Mandates: The expression const_­cast<T*>((U*)nullptr) is well-formed.
Returns: shared_ptr<T>(R, const_cast<typename shared_ptr<T>::element_type*>(r.get())) where R is r for the first overload, and std​::​move(r) for the second.
[Note 3:
The seemingly equivalent expression shared_­ptr<T>(const_­cast<T*>(r.get())) will eventually result in undefined behavior, attempting to delete the same object twice.
— end note]
template<class T, class U> shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U>&& r) noexcept;
Mandates: The expression reinterpret_­cast<T*>((U*)nullptr) is well-formed.
Returns: shared_ptr<T>(R, reinterpret_cast<typename shared_ptr<T>::element_type*>(r.get())) where R is r for the first overload, and std​::​move(r) for the second.
[Note 4:
The seemingly equivalent expression shared_­ptr<T>(reinterpret_­cast<T*>(r.get())) will eventually result in undefined behavior, attempting to delete the same object twice.
— end note]

20.3.2.2.11 get_­deleter [util.smartptr.getdeleter]

template<class D, class T> D* get_deleter(const shared_ptr<T>& p) noexcept;
Returns: If p owns a deleter d of type cv-unqualified D, returns addressof(d); otherwise returns nullptr.
The returned pointer remains valid as long as there exists a shared_­ptr instance that owns d.
[Note 1:
It is unspecified whether the pointer remains valid longer than that.
This can happen if the implementation doesn't destroy the deleter until all weak_­ptr instances that share ownership with p have been destroyed.
— end note]

20.3.2.2.12 I/O [util.smartptr.shared.io]

template<class E, class T, class Y> basic_ostream<E, T>& operator<<(basic_ostream<E, T>& os, const shared_ptr<Y>& p);
Effects: As if by: os << p.get();
Returns: os.

20.3.2.3 Class template weak_­ptr [util.smartptr.weak]

20.3.2.3.1 General [util.smartptr.weak.general]

The weak_­ptr class template stores a weak reference to an object that is already managed by a shared_­ptr.
To access the object, a weak_­ptr can be converted to a shared_­ptr using the member function lock.
namespace std { template<class T> class weak_ptr { public: using element_type = remove_extent_t<T>; // [util.smartptr.weak.const], constructors constexpr weak_ptr() noexcept; template<class Y> weak_ptr(const shared_ptr<Y>& r) noexcept; weak_ptr(const weak_ptr& r) noexcept; template<class Y> weak_ptr(const weak_ptr<Y>& r) noexcept; weak_ptr(weak_ptr&& r) noexcept; template<class Y> weak_ptr(weak_ptr<Y>&& r) noexcept; // [util.smartptr.weak.dest], destructor ~weak_ptr(); // [util.smartptr.weak.assign], assignment weak_ptr& operator=(const weak_ptr& r) noexcept; template<class Y> weak_ptr& operator=(const weak_ptr<Y>& r) noexcept; template<class Y> weak_ptr& operator=(const shared_ptr<Y>& r) noexcept; weak_ptr& operator=(weak_ptr&& r) noexcept; template<class Y> weak_ptr& operator=(weak_ptr<Y>&& r) noexcept; // [util.smartptr.weak.mod], modifiers void swap(weak_ptr& r) noexcept; void reset() noexcept; // [util.smartptr.weak.obs], observers long use_count() const noexcept; bool expired() const noexcept; shared_ptr<T> lock() const noexcept; template<class U> bool owner_before(const shared_ptr<U>& b) const noexcept; template<class U> bool owner_before(const weak_ptr<U>& b) const noexcept; }; template<class T> weak_ptr(shared_ptr<T>) -> weak_ptr<T>; }
Specializations of weak_­ptr shall be Cpp17CopyConstructible and Cpp17CopyAssignable, allowing their use in standard containers.
The template parameter T of weak_­ptr may be an incomplete type.

20.3.2.3.2 Constructors [util.smartptr.weak.const]

constexpr weak_ptr() noexcept;
Effects: Constructs an empty weak_­ptr object that stores a null pointer value.
Postconditions: use_­count() == 0.
weak_ptr(const weak_ptr& r) noexcept; template<class Y> weak_ptr(const weak_ptr<Y>& r) noexcept; template<class Y> weak_ptr(const shared_ptr<Y>& r) noexcept;
Constraints: For the second and third constructors, Y* is compatible with T*.
Effects: If r is empty, constructs an empty weak_­ptr object that stores a null pointer value; otherwise, constructs a weak_­ptr object that shares ownership with r and stores a copy of the pointer stored in r.
Postconditions: use_­count() == r.use_­count().
weak_ptr(weak_ptr&& r) noexcept; template<class Y> weak_ptr(weak_ptr<Y>&& r) noexcept;
Constraints: For the second constructor, Y* is compatible with T*.
Effects: Move constructs a weak_­ptr instance from r.
Postconditions: *this contains the old value of r.
r is empty, stores a null pointer value, and r.use_­count() == 0.

20.3.2.3.3 Destructor [util.smartptr.weak.dest]

~weak_ptr();
Effects: Destroys this weak_­ptr object but has no effect on the object its stored pointer points to.

20.3.2.3.4 Assignment [util.smartptr.weak.assign]

weak_ptr& operator=(const weak_ptr& r) noexcept; template<class Y> weak_ptr& operator=(const weak_ptr<Y>& r) noexcept; template<class Y> weak_ptr& operator=(const shared_ptr<Y>& r) noexcept;
Effects: Equivalent to weak_­ptr(r).swap(*this).
Returns: *this.
Remarks: The implementation may meet the effects (and the implied guarantees) via different means, without creating a temporary object.
weak_ptr& operator=(weak_ptr&& r) noexcept; template<class Y> weak_ptr& operator=(weak_ptr<Y>&& r) noexcept;
Effects: Equivalent to weak_­ptr(std​::​move(r)).swap(*this).
Returns: *this.

20.3.2.3.5 Modifiers [util.smartptr.weak.mod]

void swap(weak_ptr& r) noexcept;
Effects: Exchanges the contents of *this and r.
void reset() noexcept;
Effects: Equivalent to weak_­ptr().swap(*this).

20.3.2.3.6 Observers [util.smartptr.weak.obs]

long use_count() const noexcept;
Returns: 0 if *this is empty; otherwise, the number of shared_­ptr instances that share ownership with *this.
bool expired() const noexcept;
Returns: use_­count() == 0.
shared_ptr<T> lock() const noexcept;
Returns: expired() ? shared_­ptr<T>() : shared_­ptr<T>(*this), executed atomically.
template<class U> bool owner_before(const shared_ptr<U>& b) const noexcept; template<class U> bool owner_before(const weak_ptr<U>& b) const noexcept;
Returns: An unspecified value such that
  • x.owner_­before(y) defines a strict weak ordering as defined in [alg.sorting];
  • under the equivalence relation defined by owner_­before, !a.owner_­before(b) && !b.owner_­before(a), two shared_­ptr or weak_­ptr instances are equivalent if and only if they share ownership or are both empty.

20.3.2.3.7 Specialized algorithms [util.smartptr.weak.spec]

template<class T> void swap(weak_ptr<T>& a, weak_ptr<T>& b) noexcept;
Effects: Equivalent to a.swap(b).

20.3.2.4 Class template owner_­less [util.smartptr.ownerless]

The class template owner_­less allows ownership-based mixed comparisons of shared and weak pointers.
namespace std { template<class T = void> struct owner_less; template<class T> struct owner_less<shared_ptr<T>> { bool operator()(const shared_ptr<T>&, const shared_ptr<T>&) const noexcept; bool operator()(const shared_ptr<T>&, const weak_ptr<T>&) const noexcept; bool operator()(const weak_ptr<T>&, const shared_ptr<T>&) const noexcept; }; template<class T> struct owner_less<weak_ptr<T>> { bool operator()(const weak_ptr<T>&, const weak_ptr<T>&) const noexcept; bool operator()(const shared_ptr<T>&, const weak_ptr<T>&) const noexcept; bool operator()(const weak_ptr<T>&, const shared_ptr<T>&) const noexcept; }; template<> struct owner_less<void> { template<class T, class U> bool operator()(const shared_ptr<T>&, const shared_ptr<U>&) const noexcept; template<class T, class U> bool operator()(const shared_ptr<T>&, const weak_ptr<U>&) const noexcept; template<class T, class U> bool operator()(const weak_ptr<T>&, const shared_ptr<U>&) const noexcept; template<class T, class U> bool operator()(const weak_ptr<T>&, const weak_ptr<U>&) const noexcept; using is_transparent = unspecified; }; }
operator()(x, y) returns x.owner_­before(y).
[Note 1:
Note that
  • operator() defines a strict weak ordering as defined in [alg.sorting];
  • two shared_­ptr or weak_­ptr instances are equivalent under the equivalence relation defined by operator(), !operator()(a, b) && !operator()(b, a), if and only if they share ownership or are both empty.
— end note]

20.3.2.5 Class template enable_­shared_­from_­this [util.smartptr.enab]

A class T can inherit from enable_­shared_­from_­this<T> to inherit the shared_­from_­this member functions that obtain a shared_­ptr instance pointing to *this.
[Example 1: struct X: public enable_shared_from_this<X> { }; int main() { shared_ptr<X> p(new X); shared_ptr<X> q = p->shared_from_this(); assert(p == q); assert(!p.owner_before(q) && !q.owner_before(p)); // p and q share ownership } — end example]
namespace std { template<class T> class enable_shared_from_this { protected: constexpr enable_shared_from_this() noexcept; enable_shared_from_this(const enable_shared_from_this&) noexcept; enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept; ~enable_shared_from_this(); public: shared_ptr<T> shared_from_this(); shared_ptr<T const> shared_from_this() const; weak_ptr<T> weak_from_this() noexcept; weak_ptr<T const> weak_from_this() const noexcept; private: mutable weak_ptr<T> weak_this; // exposition only }; }
The template parameter T of enable_­shared_­from_­this may be an incomplete type.
constexpr enable_shared_from_this() noexcept; enable_shared_from_this(const enable_shared_from_this<T>&) noexcept;
Effects: Value-initializes weak_­this.
enable_shared_from_this<T>& operator=(const enable_shared_from_this<T>&) noexcept;
Returns: *this.
[Note 1:
weak_­this is not changed.
— end note]
shared_ptr<T> shared_from_this(); shared_ptr<T const> shared_from_this() const;
Returns: shared_­ptr<T>(weak_­this).
weak_ptr<T> weak_from_this() noexcept; weak_ptr<T const> weak_from_this() const noexcept;
Returns: weak_­this.

20.3.3 Smart pointer hash support [util.smartptr.hash]

template<class T, class D> struct hash<unique_ptr<T, D>>;
Letting UP be unique_­ptr<T, D>, the specialization hash<UP> is enabled ([unord.hash]) if and only if hash<typename UP​::​pointer> is enabled.
When enabled, for an object p of type UP, hash<UP>()(p) evaluates to the same value as hash<typename UP​::​pointer>()(p.get()).
The member functions are not guaranteed to be noexcept.
template<class T> struct hash<shared_ptr<T>>;
For an object p of type shared_­ptr<T>, hash<shared_­ptr<T>>()(p) evaluates to the same value as hash<typename shared_­ptr<T>​::​element_­type*>()(p.get()).

20.3.4 Smart pointer adaptors [smartptr.adapt]

20.3.4.1 Class template out_­ptr_­t [out.ptr.t]

out_­ptr_­t is a class template used to adapt types such as smart pointers ([smartptr]) for functions that use output pointer parameters.
[Example 1:
#include <memory> #include <cstdio> int fopen_s(std::FILE** f, const char* name, const char* mode); struct fclose_deleter { void operator()(std::FILE* f) const noexcept { std::fclose(f); } }; int main(int, char*[]) { constexpr const char* file_name = "ow.o"; std::unique_ptr<std::FILE, fclose_deleter> file_ptr; int err = fopen_s(std::out_ptr<std::FILE*>(file_ptr), file_name, "r+b"); if (err != 0) return 1; // *file_­ptr is valid return 0; } unique_­ptr can be used with out_­ptr to be passed into an output pointer-style function, without needing to hold onto an intermediate pointer value and manually delete it on error or failure.
— end example]
namespace std { template<class Smart, class Pointer, class... Args> class out_ptr_t { public: explicit out_ptr_t(Smart&, Args...); out_ptr_t(const out_ptr_t&) = delete; ~out_ptr_t(); operator Pointer*() const noexcept; operator void**() const noexcept; private: Smart& s; // exposition only tuple<Args...> a; // exposition only Pointer p; // exposition only }; }
Pointer shall meet the Cpp17NullablePointer requirements.
If Smart is a specialization of shared_­ptr and sizeof...(Args) == 0, the program is ill-formed.
[Note 1:
It is typically a user error to reset a shared_­ptr without specifying a deleter, as shared_­ptr will replace a custom deleter upon usage of reset, as specified in [util.smartptr.shared.mod].
— end note]
Program-defined specializations of out_­ptr_­t that depend on at least one program-defined type need not meet the requirements for the primary template.
Evaluations of the conversion functions on the same object may conflict ([intro.races]).
explicit out_ptr_t(Smart& smart, Args... args);
Effects: Initializes s with smart, a with std​::​forward<Args>(args)..., and value-initializes p.
[Note 2:
The constructor is not noexcept to allow for a variety of non-terminating and safe implementation strategies.
For example, an implementation can allocate a shared_­ptr's internal node in the constructor and let implementation-defined exceptions escape safely.
The destructor can then move the allocated control block in directly and avoid any other exceptions.
— end note]
~out_ptr_t();
Let SP be POINTER_­OF_­OR(Smart, Pointer) ([memory.general]).
Effects: Equivalent to:
  • -- if (p) { apply([&](auto&&... args) { s.reset(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a)); } if the expression s.reset(static_­cast<SP>(p), std​::​forward<Args>(args)...) is well-
    formed;
  • otherwise, if (p) { apply([&](auto&&... args) { s = Smart(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a)); } if is_­constructible_­v<Smart, SP, Args...> is true;
  • otherwise, the program is ill-formed.
operator Pointer*() const noexcept;
Preconditions: operator void**() has not been called on *this.
Returns: addressof(const_­cast<Pointer&>(p)).
operator void**() const noexcept;
Constraints: is_­same_­v<Pointer, void*> is false.
Mandates: is_­pointer_­v<Pointer> is true.
Preconditions: operator Pointer*() has not been called on *this.
Returns: A pointer value v such that:
  • the initial value *v is equivalent to static_­cast<void*>(p) and
  • any modification of *v that is not followed by a subsequent modification of *this affects the value of p during the destruction of *this, such that static_­cast<void*>(p) == *v.
Remarks: Accessing *v outside the lifetime of *this has undefined behavior.
[Note 3:
reinterpret_­cast<void**>(static_­cast<Pointer*>(*this)) can be a viable implementation strategy for some implementations.
— end note]

20.3.4.2 Function template out_­ptr [out.ptr]

template<class Pointer = void, class Smart, class... Args> auto out_ptr(Smart& s, Args&&... args);
Let P be Pointer if is_­void_­v<Pointer> is false, otherwise POINTER_­OF(Smart).
Returns: out_­ptr_­t<Smart, P, Args&&...>(s, std​::​forward<Args>(args)...)

20.3.4.3 Class template inout_­ptr_­t [inout.ptr.t]

inout_­ptr_­t is a class template used to adapt types such as smart pointers ([smartptr]) for functions that use output pointer parameters whose dereferenced values may first be deleted before being set to another allocated value.
[Example 1: #include <memory> struct star_fish* star_fish_alloc(); int star_fish_populate(struct star_fish** ps, const char* description); struct star_fish_deleter { void operator() (struct star_fish* c) const noexcept; }; using star_fish_ptr = std::unique_ptr<star_fish, star_fish_deleter>; int main(int, char*[]) { star_fish_ptr peach(star_fish_alloc()); // ... // used, need to re-make int err = star_fish_populate(std::inout_ptr(peach), "caring clown-fish liker"); return err; }
A unique_­ptr can be used with inout_­ptr to be passed into an output pointer-style function.
The original value will be properly deleted according to the function it is used with and a new value reset in its place.
— end example]
namespace std { template<class Smart, class Pointer, class... Args> class inout_ptr_t { public: explicit inout_ptr_t(Smart&, Args...); inout_ptr_t(const inout_ptr_t&) = delete; ~inout_ptr_t(); operator Pointer*() const noexcept; operator void**() const noexcept; private: Smart& s; // exposition only tuple<Args...> a; // exposition only Pointer p; // exposition only }; }
Pointer shall meet the Cpp17NullablePointer requirements.
If Smart is a specialization of shared_­ptr, the program is ill-formed.
[Note 1:
It is impossible to properly acquire unique ownership of the managed resource from a shared_­ptr given its shared ownership model.
— end note]
Program-defined specializations of inout_­ptr_­t that depend on at least one program-defined type need not meet the requirements for the primary template.
Evaluations of the conversion functions on the same object may conflict ([intro.races]).
explicit inout_ptr_t(Smart& smart, Args... args);
Effects: Initializes s with smart, a with std​::​forward<Args>(args)..., and p to either
  • smart if is_­pointer_­v<Smart> is true,
  • otherwise, smart.get().
Remarks: An implementation can call s.release().
[Note 2:
The constructor is not noexcept to allow for a variety of non-terminating and safe implementation strategies.
For example, an intrusive pointer implementation with a control block can allocate in the constructor and safely fail with an exception.
— end note]
~inout_ptr_t();
Let SP be POINTER_­OF_­OR(Smart, Pointer) ([memory.general]).
Let release-statement be s.release(); if an implementation does not call s.release() in the constructor.
Otherwise, it is empty.
Effects: Equivalent to:
  • -- if (p) { apply([&](auto&&... args) { s = Smart( static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a)); } if is_­pointer_­v<Smart> is true;
  • otherwise, if (p) { apply([&](auto&&... args) { release-statement; s.reset(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a)); } if the expression s.reset(static_­cast<SP>(p), std​::​forward<Args>(args)...) is well-
    formed;
  • otherwise, if (p) { apply([&](auto&&... args) { release-statement; s = Smart(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a)); } if is_­constructible_­v<Smart, SP, Args...> is true;
  • otherwise, the program is ill-formed.
operator Pointer*() const noexcept;
Preconditions: operator void**() has not been called on *this.
Returns: addressof(const_­cast<Pointer&>(p)).
operator void**() const noexcept;
Constraints: is_­same_­v<Pointer, void*> is false.
Mandates: is_­pointer_­v<Pointer> is true.
Preconditions: operator Pointer*() has not been called on *this.
Returns: A pointer value v such that:
  • the initial value *v is equivalent to static_­cast<void*>(p) and
  • any modification of *v that is not followed by subsequent modification of *this affects the value of p during the destruction of *this, such that static_­cast<void*>(p) == *v.
Remarks: Accessing *v outside the lifetime of *this has undefined behavior.
[Note 3:
reinterpret_­cast<void**>(static_­cast<Pointer*>(*this)) can be a viable implementation strategy for some implementations.
— end note]

20.3.4.4 Function template inout_­ptr [inout.ptr]

template<class Pointer = void, class Smart, class... Args> auto inout_ptr(Smart& s, Args&&... args);
Let P be Pointer if is_­void_­v<Pointer> is false, otherwise POINTER_­OF(Smart).
Returns: inout_­ptr_­t<Smart, P, Args&&...>(s, std​::​forward<Args>(args)...).

20.4 Memory resources [mem.res]

20.4.1 Header <memory_­resource> synopsis [mem.res.syn]

namespace std::pmr { // [mem.res.class], class memory_­resource class memory_resource; bool operator==(const memory_resource& a, const memory_resource& b) noexcept; // [mem.poly.allocator.class], class template polymorphic_­allocator template<class Tp = byte> class polymorphic_allocator; template<class T1, class T2> bool operator==(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) noexcept; // [mem.res.global], global memory resources memory_resource* new_delete_resource() noexcept; memory_resource* null_memory_resource() noexcept; memory_resource* set_default_resource(memory_resource* r) noexcept; memory_resource* get_default_resource() noexcept; // [mem.res.pool], pool resource classes struct pool_options; class synchronized_pool_resource; class unsynchronized_pool_resource; class monotonic_buffer_resource; }

20.4.2 Class memory_­resource [mem.res.class]

20.4.2.1 General [mem.res.class.general]

The memory_­resource class is an abstract interface to an unbounded set of classes encapsulating memory resources.
namespace std::pmr { class memory_resource { static constexpr size_t max_align = alignof(max_align_t); // exposition only public: memory_resource() = default; memory_resource(const memory_resource&) = default; virtual ~memory_resource(); memory_resource& operator=(const memory_resource&) = default; [[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align); void deallocate(void* p, size_t bytes, size_t alignment = max_align); bool is_equal(const memory_resource& other) const noexcept; private: virtual void* do_allocate(size_t bytes, size_t alignment) = 0; virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; }; }

20.4.2.2 Public member functions [mem.res.public]

~memory_resource();
Effects: Destroys this memory_­resource.
[[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align);
Effects: Allocates storage by calling do_­allocate(bytes, alignment) and implicitly creates objects within the allocated region of storage.
Returns: A pointer to a suitable created object ([intro.object]) in the allocated region of storage.
Throws: What and when the call to do_­allocate throws.
void deallocate(void* p, size_t bytes, size_t alignment = max_align);
Effects: Equivalent to do_­deallocate(p, bytes, alignment).
bool is_equal(const memory_resource& other) const noexcept;
Effects: Equivalent to: return do_­is_­equal(other);

20.4.2.3 Private virtual member functions [mem.res.private]

virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
Preconditions: alignment is a power of two.
Returns: A derived class shall implement this function to return a pointer to allocated storage ([basic.stc.dynamic.allocation]) with a size of at least bytes, aligned to the specified alignment.
Throws: A derived class implementation shall throw an appropriate exception if it is unable to allocate memory with the requested size and alignment.
virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;
Preconditions: p was returned from a prior call to allocate(bytes, alignment) on a memory resource equal to *this, and the storage at p has not yet been deallocated.
Effects: A derived class shall implement this function to dispose of allocated storage.
Throws: Nothing.
virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
Returns: A derived class shall implement this function to return true if memory allocated from this can be deallocated from other and vice-versa, otherwise false.
[Note 1:
It is possible that the most-derived type of other does not match the type of this.
For a derived class D, an implementation of this function can immediately return false if dynamic_­cast<const D*>(&other) == nullptr.
— end note]

20.4.2.4 Equality [mem.res.eq]

bool operator==(const memory_resource& a, const memory_resource& b) noexcept;
Returns: &a == &b || a.is_­equal(b).

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

20.4.3.1 General [mem.poly.allocator.class.general]

A specialization of class template pmr​::​polymorphic_­allocator meets the Cpp17Allocator requirements ([allocator.requirements.general]).
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); polymorphic_allocator select_on_container_copy_construction() const; memory_resource* resource() const; }; }

20.4.3.2 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 1:
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.4.3.3 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 1:
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 2:
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 3:
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: allocator_traits<polymorphic_allocator>::destroy(*this, 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.
polymorphic_allocator select_on_container_copy_construction() const;
Returns: polymorphic_­allocator().
[Note 4:
The memory resource is not propagated.
— end note]
memory_resource* resource() const;
Returns: memory_­rsrc.

20.4.3.4 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().

20.4.4 Access to program-wide memory_­resource objects [mem.res.global]

memory_resource* new_delete_resource() noexcept;
Returns: A pointer to a static-duration object of a type derived from memory_­resource that can serve as a resource for allocating memory using ​::​operator new and ​::​operator delete.
The same value is returned every time this function is called.
For a return value p and a memory resource r, p->is_­equal(r) returns &r == p.
memory_resource* null_memory_resource() noexcept;
Returns: A pointer to a static-duration object of a type derived from memory_­resource for which allocate() always throws bad_­alloc and for which deallocate() has no effect.
The same value is returned every time this function is called.
For a return value p and a memory resource r, p->is_­equal(r) returns &r == p.
The default memory resource pointer is a pointer to a memory resource that is used by certain facilities when an explicit memory resource is not supplied through the interface.
Its initial value is the return value of new_­delete_­resource().
memory_resource* set_default_resource(memory_resource* r) noexcept;
Effects: If r is non-null, sets the value of the default memory resource pointer to r, otherwise sets the default memory resource pointer to new_­delete_­resource().
Returns: The previous value of the default memory resource pointer.
Remarks: Calling the set_­default_­resource and get_­default_­resource functions shall not incur a data race.
A call to the set_­default_­resource function shall synchronize with subsequent calls to the set_­default_­resource and get_­default_­resource functions.
memory_resource* get_default_resource() noexcept;
Returns: The current value of the default memory resource pointer.

20.4.5 Pool resource classes [mem.res.pool]

20.4.5.1 Classes synchronized_­pool_­resource and unsynchronized_­pool_­resource [mem.res.pool.overview]

The synchronized_­pool_­resource and unsynchronized_­pool_­resource classes (collectively called pool resource classes) are general-purpose memory resources having the following qualities:
  • Each resource frees its allocated memory on destruction, even if deallocate has not been called for some of the allocated blocks.
  • A pool resource consists of a collection of pools, serving requests for different block sizes.
    Each individual pool manages a collection of chunks that are in turn divided into blocks of uniform size, returned via calls to do_­allocate.
    Each call to do_­allocate(size, alignment) is dispatched to the pool serving the smallest blocks accommodating at least size bytes.
  • When a particular pool is exhausted, allocating a block from that pool results in the allocation of an additional chunk of memory from the upstream allocator (supplied at construction), thus replenishing the pool.
    With each successive replenishment, the chunk size obtained increases geometrically.
    [Note 1:
    By allocating memory in chunks, the pooling strategy increases the chance that consecutive allocations will be close together in memory.
    — end note]
  • Allocation requests that exceed the largest block size of any pool are fulfilled directly from the upstream allocator.
  • A pool_­options struct may be passed to the pool resource constructors to tune the largest block size and the maximum chunk size.
A synchronized_­pool_­resource may be accessed from multiple threads without external synchronization and may have thread-specific pools to reduce synchronization costs.
An unsynchronized_­pool_­resource class may not be accessed from multiple threads simultaneously and thus avoids the cost of synchronization entirely in single-threaded applications.
namespace std::pmr { struct pool_options { size_t max_blocks_per_chunk = 0; size_t largest_required_pool_block = 0; }; class synchronized_pool_resource : public memory_resource { public: synchronized_pool_resource(const pool_options& opts, memory_resource* upstream); synchronized_pool_resource() : synchronized_pool_resource(pool_options(), get_default_resource()) {} explicit synchronized_pool_resource(memory_resource* upstream) : synchronized_pool_resource(pool_options(), upstream) {} explicit synchronized_pool_resource(const pool_options& opts) : synchronized_pool_resource(opts, get_default_resource()) {} synchronized_pool_resource(const synchronized_pool_resource&) = delete; virtual ~synchronized_pool_resource(); synchronized_pool_resource& operator=(const synchronized_pool_resource&) = delete; void release(); memory_resource* upstream_resource() const; pool_options options() const; protected: void* do_allocate(size_t bytes, size_t alignment) override; void do_deallocate(void* p, size_t bytes, size_t alignment) override; bool do_is_equal(const memory_resource& other) const noexcept override; }; class unsynchronized_pool_resource : public memory_resource { public: unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream); unsynchronized_pool_resource() : unsynchronized_pool_resource(pool_options(), get_default_resource()) {} explicit unsynchronized_pool_resource(memory_resource* upstream) : unsynchronized_pool_resource(pool_options(), upstream) {} explicit unsynchronized_pool_resource(const pool_options& opts) : unsynchronized_pool_resource(opts, get_default_resource()) {} unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; virtual ~unsynchronized_pool_resource(); unsynchronized_pool_resource& operator=(const unsynchronized_pool_resource&) = delete; void release(); memory_resource* upstream_resource() const; pool_options options() const; protected: void* do_allocate(size_t bytes, size_t alignment) override; void do_deallocate(void* p, size_t bytes, size_t alignment) override; bool do_is_equal(const memory_resource& other) const noexcept override; }; }

20.4.5.2 pool_­options data members [mem.res.pool.options]

The members of pool_­options comprise a set of constructor options for pool resources.
The effect of each option on the pool resource behavior is described below:
size_t max_blocks_per_chunk;
The maximum number of blocks that will be allocated at once from the upstream memory resource ([mem.res.monotonic.buffer]) to replenish a pool.
If the value of max_­blocks_­per_­chunk is zero or is greater than an implementation-defined limit, that limit is used instead.
The implementation may choose to use a smaller value than is specified in this field and may use different values for different pools.
size_t largest_required_pool_block;
The largest allocation size that is required to be fulfilled using the pooling mechanism.
Attempts to allocate a single block larger than this threshold will be allocated directly from the upstream memory resource.
If largest_­required_­pool_­block is zero or is greater than an implementation-defined limit, that limit is used instead.
The implementation may choose a pass-through threshold larger than specified in this field.

20.4.5.3 Constructors and destructors [mem.res.pool.ctor]

synchronized_pool_resource(const pool_options& opts, memory_resource* upstream); unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
Preconditions: upstream is the address of a valid memory resource.
Effects: Constructs a pool resource object that will obtain memory from upstream whenever the pool resource is unable to satisfy a memory request from its own internal data structures.
The resulting object will hold a copy of upstream, but will not own the resource to which upstream points.
[Note 1:
The intention is that calls to upstream->allocate() will be substantially fewer than calls to this->allocate() in most cases.
— end note]
The behavior of the pooling mechanism is tuned according to the value of the opts argument.
Throws: Nothing unless upstream->allocate() throws.
It is unspecified if, or under what conditions, this constructor calls upstream->allocate().
virtual ~synchronized_pool_resource(); virtual ~unsynchronized_pool_resource();
Effects: Calls release().

20.4.5.4 Members [mem.res.pool.mem]

void release();
Effects: Calls upstream_­resource()->deallocate() as necessary to release all allocated memory.
[Note 1:
The memory is released back to upstream_­resource() even if deallocate has not been called for some of the allocated blocks.
— end note]
memory_resource* upstream_resource() const;
Returns: The value of the upstream argument provided to the constructor of this object.
pool_options options() const;
Returns: The options that control the pooling behavior of this resource.
The values in the returned struct may differ from those supplied to the pool resource constructor in that values of zero will be replaced with implementation-defined defaults, and sizes may be rounded to unspecified granularity.
void* do_allocate(size_t bytes, size_t alignment) override;
Effects: If the pool selected for a block of size bytes is unable to satisfy the memory request from its own internal data structures, it will call upstream_­resource()->allocate() to obtain more memory.
If bytes is larger than that which the largest pool can handle, then memory will be allocated using upstream_­resource()->allocate().
Returns: A pointer to allocated storage ([basic.stc.dynamic.allocation]) with a size of at least bytes.
The size and alignment of the allocated memory shall meet the requirements for a class derived from memory_­resource ([mem.res.class]).
Throws: Nothing unless upstream_­resource()->allocate() throws.
void do_deallocate(void* p, size_t bytes, size_t alignment) override;
Effects: Returns the memory at p to the pool.
It is unspecified if, or under what circumstances, this operation will result in a call to upstream_­resource()->deallocate().
Throws: Nothing.
bool do_is_equal(const memory_resource& other) const noexcept override;
Returns: this == &other.

20.4.6 Class monotonic_­buffer_­resource [mem.res.monotonic.buffer]

20.4.6.1 General [mem.res.monotonic.buffer.general]

A monotonic_­buffer_­resource is a special-purpose memory resource intended for very fast memory allocations in situations where memory is used to build up a few objects and then is released all at once when the memory resource object is destroyed.
namespace std::pmr { class monotonic_buffer_resource : public memory_resource { memory_resource* upstream_rsrc; // exposition only void* current_buffer; // exposition only size_t next_buffer_size; // exposition only public: explicit monotonic_buffer_resource(memory_resource* upstream); monotonic_buffer_resource(size_t initial_size, memory_resource* upstream); monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream); monotonic_buffer_resource() : monotonic_buffer_resource(get_default_resource()) {} explicit monotonic_buffer_resource(size_t initial_size) : monotonic_buffer_resource(initial_size, get_default_resource()) {} monotonic_buffer_resource(void* buffer, size_t buffer_size) : monotonic_buffer_resource(buffer, buffer_size, get_default_resource()) {} monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; virtual ~monotonic_buffer_resource(); monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete; void release(); memory_resource* upstream_resource() const; protected: void* do_allocate(size_t bytes, size_t alignment) override; void do_deallocate(void* p, size_t bytes, size_t alignment) override; bool do_is_equal(const memory_resource& other) const noexcept override; }; }

20.4.6.2 Constructors and destructor [mem.res.monotonic.buffer.ctor]

explicit monotonic_buffer_resource(memory_resource* upstream); monotonic_buffer_resource(size_t initial_size, memory_resource* upstream);
Preconditions: upstream is the address of a valid memory resource.
initial_­size, if specified, is greater than zero.
Effects: Sets upstream_­rsrc to upstream and current_­buffer to nullptr.
If initial_­size is specified, sets next_­buffer_­size to at least initial_­size; otherwise sets next_­buffer_­size to an implementation-defined size.
monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream);
Preconditions: upstream is the address of a valid memory resource.
buffer_­size is no larger than the number of bytes in buffer.
Effects: Sets upstream_­rsrc to upstream, current_­buffer to buffer, and next_­buffer_­size to buffer_­size (but not less than 1), then increases next_­buffer_­size by an implementation-defined growth factor (which need not be integral).
~monotonic_buffer_resource();
Effects: Calls release().

20.4.6.3 Members [mem.res.monotonic.buffer.mem]

void release();
Effects: Calls upstream_­rsrc->deallocate() as necessary to release all allocated memory.
Resets current_­buffer and next_­buffer_­size to their initial values at construction.
[Note 1:
The memory is released back to upstream_­rsrc even if some blocks that were allocated from this have not been deallocated from this.
— end note]
memory_resource* upstream_resource() const;
Returns: The value of upstream_­rsrc.
void* do_allocate(size_t bytes, size_t alignment) override;
Effects: If the unused space in current_­buffer can fit a block with the specified bytes and alignment, then allocate the return block from current_­buffer; otherwise set current_­buffer to upstream_­rsrc->allocate(n, m), where n is not less than max(bytes, next_­buffer_­size) and m is not less than alignment, and increase next_­buffer_­size by an implementation-defined growth factor (which need not be integral), then allocate the return block from the newly-allocated current_­buffer.
Returns: A pointer to allocated storage ([basic.stc.dynamic.allocation]) with a size of at least bytes.
The size and alignment of the allocated memory shall meet the requirements for a class derived from memory_­resource ([mem.res.class]).
Throws: Nothing unless upstream_­rsrc->allocate() throws.
void do_deallocate(void* p, size_t bytes, size_t alignment) override;
Effects: None.
Throws: Nothing.
Remarks: Memory used by this resource increases monotonically until its destruction.
bool do_is_equal(const memory_resource& other) const noexcept override;
Returns: this == &other.

20.5 Class template scoped_­allocator_­adaptor [allocator.adaptor]

20.5.1 Header <scoped_­allocator> synopsis [allocator.adaptor.syn]

namespace std { // class template scoped_­allocator_­adaptor template<class OuterAlloc, class... InnerAlloc> class scoped_allocator_adaptor; // [scoped.adaptor.operators], scoped allocator operators template<class OuterA1, class OuterA2, class... InnerAllocs> bool operator==(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a, const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept; }
The class template scoped_­allocator_­adaptor is an allocator template that specifies an allocator resource (the outer allocator) to be used by a container (as any other allocator does) and also specifies an inner allocator resource to be passed to the constructor of every element within the container.
This adaptor is instantiated with one outer and zero or more inner allocator types.
If instantiated with only one allocator type, the inner allocator becomes the scoped_­allocator_­adaptor itself, thus using the same allocator resource for the container and every element within the container and, if the elements themselves are containers, each of their elements recursively.
If instantiated with more than one allocator, the first allocator is the outer allocator for use by the container, the second allocator is passed to the constructors of the container's elements, and, if the elements themselves are containers, the third allocator is passed to the elements' elements, and so on.
If containers are nested to a depth greater than the number of allocators, the last allocator is used repeatedly, as in the single-allocator case, for any remaining recursions.
[Note 1:
The scoped_­allocator_­adaptor is derived from the outer allocator type so it can be substituted for the outer allocator type in most expressions.
— end note]
namespace std { template<class OuterAlloc, class... InnerAllocs> class scoped_allocator_adaptor : public OuterAlloc { private: using OuterTraits = allocator_traits<OuterAlloc>; // exposition only scoped_allocator_adaptor<InnerAllocs...> inner; // exposition only public: using outer_allocator_type = OuterAlloc; using inner_allocator_type = see below; using value_type = typename OuterTraits::value_type; using size_type = typename OuterTraits::size_type; using difference_type = typename OuterTraits::difference_type; using pointer = typename OuterTraits::pointer; using const_pointer = typename OuterTraits::const_pointer; using void_pointer = typename OuterTraits::void_pointer; using const_void_pointer = typename OuterTraits::const_void_pointer; using propagate_on_container_copy_assignment = see below; using propagate_on_container_move_assignment = see below; using propagate_on_container_swap = see below; using is_always_equal = see below; template<class Tp> struct rebind { using other = scoped_allocator_adaptor< OuterTraits::template rebind_alloc<Tp>, InnerAllocs...>; }; scoped_allocator_adaptor(); template<class OuterA2> scoped_allocator_adaptor(OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept; scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept; scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept; template<class OuterA2> scoped_allocator_adaptor( const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other) noexcept; template<class OuterA2> scoped_allocator_adaptor( scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other) noexcept; scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) = default; scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default; ~scoped_allocator_adaptor(); inner_allocator_type& inner_allocator() noexcept; const inner_allocator_type& inner_allocator() const noexcept; outer_allocator_type& outer_allocator() noexcept; const outer_allocator_type& outer_allocator() const noexcept; [[nodiscard]] pointer allocate(size_type n); [[nodiscard]] pointer allocate(size_type n, const_void_pointer hint); void deallocate(pointer p, size_type n); size_type max_size() const; template<class T, class... Args> void construct(T* p, Args&&... args); template<class T> void destroy(T* p); scoped_allocator_adaptor select_on_container_copy_construction() const; }; template<class OuterAlloc, class... InnerAllocs> scoped_allocator_adaptor(OuterAlloc, InnerAllocs...) -> scoped_allocator_adaptor<OuterAlloc, InnerAllocs...>; }

20.5.2 Member types [allocator.adaptor.types]

using inner_allocator_type = see below;
Type: scoped_­allocator_­adaptor<OuterAlloc> if sizeof...(InnerAllocs) is zero; otherwise,
scoped_­allocator_­adaptor<InnerAllocs...>.
using propagate_on_container_copy_assignment = see below;
Type: true_­type if allocator_­traits<A>​::​propagate_­on_­container_­copy_­assignment​::​value is true for any A in the set of OuterAlloc and InnerAllocs...; otherwise, false_­type.
using propagate_on_container_move_assignment = see below;
Type: true_­type if allocator_­traits<A>​::​propagate_­on_­container_­move_­assignment​::​value is true for any A in the set of OuterAlloc and InnerAllocs...; otherwise, false_­type.
using propagate_on_container_swap = see below;
Type: true_­type if allocator_­traits<A>​::​propagate_­on_­container_­swap​::​value is true for any A in the set of OuterAlloc and InnerAllocs...; otherwise, false_­type.
using is_always_equal = see below;
Type: true_­type if allocator_­traits<A>​::​is_­always_­equal​::​value is true for every A in the set of OuterAlloc and InnerAllocs...; otherwise, false_­type.

20.5.3 Constructors [allocator.adaptor.cnstr]

scoped_allocator_adaptor();
Effects: Value-initializes the OuterAlloc base class and the inner allocator object.
template<class OuterA2> scoped_allocator_adaptor(OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept;
Constraints: is_­constructible_­v<OuterAlloc, OuterA2> is true.
Effects: Initializes the OuterAlloc base class with std​::​forward<OuterA2>(outerAlloc) and inner with innerAllocs... (hence recursively initializing each allocator within the adaptor with the corresponding allocator from the argument list).
scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept;
Effects: Initializes each allocator within the adaptor with the corresponding allocator from other.
scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept;
Effects: Move constructs each allocator within the adaptor with the corresponding allocator from other.
template<class OuterA2> scoped_allocator_adaptor( const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other) noexcept;
Constraints: is_­constructible_­v<OuterAlloc, const OuterA2&> is true.
Effects: Initializes each allocator within the adaptor with the corresponding allocator from other.
template<class OuterA2> scoped_allocator_adaptor(scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other) noexcept;
Constraints: is_­constructible_­v<OuterAlloc, OuterA2> is true.
Effects: Initializes each allocator within the adaptor with the corresponding allocator rvalue from other.

20.5.4 Members [allocator.adaptor.members]

In the construct member functions, OUTERMOST(x) is OUTERMOST(x.outer_­allocator()) if the expression x.outer_­allocator() is valid ([temp.deduct]) and x otherwise; OUTERMOST_­ALLOC_­TRAITS(x) is allocator_­traits<remove_­reference_­t<decltype(OUTERMOST(x))>>.
[Note 1:
OUTERMOST(x) and OUTERMOST_­ALLOC_­TRAITS(x) are recursive operations.
It is incumbent upon the definition of outer_­allocator() to ensure that the recursion terminates.
It will terminate for all instantiations of scoped_­allocator_­adaptor.
— end note]
inner_allocator_type& inner_allocator() noexcept; const inner_allocator_type& inner_allocator() const noexcept;
Returns: *this if sizeof...(InnerAllocs) is zero; otherwise, inner.
outer_allocator_type& outer_allocator() noexcept;
Returns: static_­cast<OuterAlloc&>(*this).
const outer_allocator_type& outer_allocator() const noexcept;
Returns: static_­cast<const OuterAlloc&>(*this).
[[nodiscard]] pointer allocate(size_type n);
Returns: allocator_­traits<OuterAlloc>​::​allocate(outer_­allocator(), n).
[[nodiscard]] pointer allocate(size_type n, const_void_pointer hint);
Returns: allocator_­traits<OuterAlloc>​::​allocate(outer_­allocator(), n, hint).
void deallocate(pointer p, size_type n) noexcept;
Effects: As if by: allocator_­traits<OuterAlloc>​::​deallocate(outer_­allocator(), p, n);
size_type max_size() const;
Returns: allocator_­traits<OuterAlloc>​::​max_­size(outer_­allocator()).
template<class T, class... Args> void construct(T* p, Args&&... args);
Effects: Equivalent to: apply([p, this](auto&&... newargs) { OUTERMOST_ALLOC_TRAITS(*this)::construct( OUTERMOST(*this), p, std::forward<decltype(newargs)>(newargs)...); }, uses_allocator_construction_args<T>(inner_allocator(), std::forward<Args>(args)...));
template<class T> void destroy(T* p);
Effects: Calls OUTERMOST_­ALLOC_­TRAITS(*this)​::​destroy(OUTERMOST(*this), p).
scoped_allocator_adaptor select_on_container_copy_construction() const;
Returns: A new scoped_­allocator_­adaptor object where each allocator a1 within the adaptor is initialized with allocator_­traits<A1>​::​select_­on_­container_­copy_­construction(a2), where A1 is the type of a1 and a2 is the corresponding allocator in *this.

20.5.5 Operators [scoped.adaptor.operators]

template<class OuterA1, class OuterA2, class... InnerAllocs> bool operator==(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a, const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept;
Returns: If sizeof...(InnerAllocs) is zero, a.outer_allocator() == b.outer_allocator() otherwise a.outer_allocator() == b.outer_allocator() && a.inner_allocator() == b.inner_allocator()