[util.smartptr.shared] (original) (raw)
20 Memory management library [mem]
20.3 Smart pointers [smartptr]
20.3.2 Shared-ownership pointers [util.sharedptr]
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.
Ashared_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>;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);~shared_ptr(); 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);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); 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; size_t owner_hash() const noexcept;template<class U> bool owner_equal(const shared_ptr<U>& b) const noexcept;template<class U> bool owner_equal(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 contextually convertible to bool, allowing their use in boolean expressions and declarations in conditions.
The template parameter T of shared_ptrmay 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)) { } — _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 [smartptr], a pointer type Y* is said to becompatible witha pointer type T* when eitherY* is convertible to T* orY 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]).
Postconditions: use_count() == 0 && get() == nullptr.
Constraints: When T is an array type, the expression delete[] p is well-formed and eitherT is U[N] and Y(*)[N] is convertible to T*, orT is U[] and Y(*)[] is convertible to T*.
When T is not an array type, the expression delete p is well-formed andY* is convertible to T*.
Mandates: Y is a complete type.
Preconditions: The expressiondelete[] p, when T is an array type, ordelete 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_ptrthat 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.
Constraints: is_move_constructible_v<D> is true, andd(p) is a well-formed expression.
For the first two overloads:
- If T is an array type, then eitherT is U[N] and Y(*)[N] is convertible to T*, orT 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 Dinitialized with std::move(d) do not throw exceptions.
The expression d(p)has well-defined behavior and does not throw exceptions.
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.
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 emptyshared_ptr instance with a non-null stored pointer.
— _end note_]
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().
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 ofr.
r is empty, and r.get() == nullptr.
Constraints: Y* is compatible with T*.
Effects: Constructs a shared_ptr object that shares ownership withr 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().
Constraints: Y* is compatible with T* andunique_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]
Effects:
- If *this is empty or shares ownership with anothershared_ptr instance (use_count() > 1), there are no side effects.
- Otherwise, if *this owns an objectp 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 *thisdecreases the number of instances that share ownership with *thisby 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]
Effects: Equivalent to shared_ptr(r).swap(*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_]
Effects: Equivalent to shared_ptr(std::move(r)).swap(*this).
Effects: Equivalent to shared_ptr(std::move(r)).swap(*this).
20.3.2.2.5 Modifiers [util.smartptr.shared.mod]
Effects: Exchanges the contents of *this and r.
Effects: Equivalent to shared_ptr().swap(*this).
Effects: Equivalent to shared_ptr(p).swap(*this).
Effects: Equivalent to shared_ptr(p, d).swap(*this).
Effects: Equivalent to shared_ptr(p, d, a).swap(*this).
20.3.2.2.6 Observers [util.smartptr.shared.obs]
Returns: The stored pointer.
Preconditions: get() != nullptr.
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.
Preconditions: get() != nullptr.
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.
Preconditions: get() != nullptr && i >= 0.
If T is U[N], i < N.
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.
Returns: The number of shared_ptr objects, *this included, that share ownership with *this, or 0 when *this is empty.
[Note 1:
get() == nullptrdoes 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_]
Returns: get() != nullptr.
Returns: An unspecified value such that
- owner_before(b) defines a strict weak ordering as defined in [alg.sorting];
- !owner_before(b) && !b.owner_before(*this) is trueif and only if owner_equal(b) is true.
Returns: An unspecified value such that, for any object x where owner_equal(x) is true,owner_hash() == x.owner_hash() is true.
Returns: true if and only if*this and b share ownership or are both empty.
Otherwise returns false.
Remarks: owner_equal is an equivalence relation.
20.3.2.2.7 Creation [util.smartptr.shared.create]
The common requirements that apply to allmake_shared,allocate_shared,make_shared_for_overwrite, andallocate_shared_for_overwrite overloads, unless specified otherwise, are described below.
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, pu, v) or
- allocator_traits<A2>::construct(a2, pu, l...)
respectively, where pu is a pointer of type remove_cv_t<U>* pointing to storage suitable to hold an object of type remove_cv_t<U> anda2 of type A2 is a potentially rebound copy of the allocator a passed to allocate_shared.
- 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 initializes this (sub)object via the expression allocator_traits<A2>::construct(a2, pu), where pu is a pointer of type remove_cv_t<U>* pointing to storage suitable to hold an object of type remove_cv_t<U> anda2 of type A2 is a potentially rebound copy of the allocator a passed to allocate_shared.
- When a (sub)object of non-array type U is initialized bymake_shared_for_overwrite orallocate_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,make_shared_for_overwrite, or allocate_shared_for_overwrite is to be destroyed, it is destroyed via the expression pu->~U() wherepu 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 expressionallocator_traits<A2>::destroy(a2, pu) wherepu is a pointer of type remove_cv_t<U>* pointing to that object of type remove_cv_t<U> anda2 of type A2 is a potentially rebound copy of the allocator a passed to allocate_shared.
[Note 2:
These functions will typically allocate more memory than sizeof(T) to allow for internal bookkeeping structures such as reference counts.
— _end note_]
Constraints: T is not an array type.
Returns: A shared_ptr to an object of type Twith an initial value T(std::forward<Args>(args)...).
Remarks: The shared_ptr constructors called by these functions enable shared_from_thiswith the address of the newly constructed object of type T.
[Example 1: shared_ptr<int> p = make_shared<int>(); shared_ptr<vector<int>> q = make_shared<vector<int>>(16, 1); — _end example_]
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<double[][2][2]> q = make_shared<double[][2][2]>(6); — _end example_]
Constraints: T is of the form U[N].
Returns: A shared_ptr to an object of type Twith a default initial value.
[Example 3: shared_ptr<double[1024]> p = make_shared<double[1024]>(); shared_ptr<double[6][2][2]> q = make_shared<double[6][2][2]>(); — _end example_]
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<double[][2]> q = make_shared<double[][2]>(6, {1.0, 0.0}); shared_ptr<vector<int>[]> r = make_shared<vector<int>[]>(4, {1, 2}); — _end example_]
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<double[6][2]> q = make_shared<double[6][2]>({1.0, 0.0}); shared_ptr<vector<int>[4]> r = make_shared<vector<int>[4]>({1, 2}); — _end example_]
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<double[1024]> q = make_shared_for_overwrite<double[1024]>(); — _end example_]
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); — _end example_]
20.3.2.2.8 Comparison [util.smartptr.shared.cmp]
Returns: a.get() == b.get().
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_]
Returns: compare_three_way()(a.get(), static_cast<typename shared_ptr<T>::element_type*>(nullptr))
20.3.2.2.10 Casts [util.smartptr.shared.cast]
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, andstd::move(r) for the second.
[Note 1:
The seemingly equivalent expressionshared_ptr<T>(static_cast<T*>(r.get()))can result in undefined behavior, attempting to delete the same object twice.
— _end note_]
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, andstd::move(r) for the second.
- Otherwise, shared_ptr<T>().
[Note 2:
The seemingly equivalent expressionshared_ptr<T>(dynamic_cast<T*>(r.get())) can result in undefined behavior, attempting to delete the same object twice.
— _end note_]
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, andstd::move(r) for the second.
[Note 3:
The seemingly equivalent expressionshared_ptr<T>(const_cast<T*>(r.get())) can result in undefined behavior, attempting to delete the same object twice.
— _end note_]
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, andstd::move(r) for the second.
[Note 4:
The seemingly equivalent expressionshared_ptr<T>(reinterpret_cast<T*>(r.get())) can result in undefined behavior, attempting to delete the same object twice.
— _end note_]
20.3.2.2.11 get_deleter [util.smartptr.getdeleter]
Returns: If p owns a deleter d of type cv-unqualifiedD, 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 withp have been destroyed.
— _end note_]