20 Memory management library [mem]

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 35).
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 36).
[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 30), 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 30), 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 31).
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 33) 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: i < 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()).
template<class U> constexpr 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() != nullptr.
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() != nullptr.
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() != nullptr && 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() != nullptr.
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() != nullptr && 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(std​::​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.
Then, equivalent to:
  • s.reset(); if the expression s.reset() is well-formed;
  • otherwise, s = Smart(); if is_constructible_v<Smart> is true;
  • otherwise, the program is ill-formed.
[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, release-statement; 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, release-statement; 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 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)...).