В shared_ptr шаблоне класса хранится указатель, обычно получаемый через new. shared_ptr реализует семантику долевого владения; последний оставшийся владелец указателя отвечает за уничтожение объекта или иное освобождение ресурсов, связанных с сохраненным указателем. А shared_ptr называется пустым, если ему не принадлежит указатель.
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; 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; 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); constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { } // [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>; // [util.smartptr.shared.create], shared_ptr creation template<class T, class... Args> shared_ptr<T> make_shared(Args&&... args); template<class T, class A, class... Args> shared_ptr<T> allocate_shared(const A& a, Args&&... args); // [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> bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator>(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator<=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator>=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template <class T> bool operator==(const shared_ptr<T>& a, nullptr_t) noexcept; template <class T> bool operator==(nullptr_t, const shared_ptr<T>& b) noexcept; template <class T> bool operator!=(const shared_ptr<T>& a, nullptr_t) noexcept; template <class T> bool operator!=(nullptr_t, const shared_ptr<T>& b) noexcept; template <class T> bool operator<(const shared_ptr<T>& a, nullptr_t) noexcept; template <class T> bool operator<(nullptr_t, const shared_ptr<T>& b) noexcept; template <class T> bool operator<=(const shared_ptr<T>& a, nullptr_t) noexcept; template <class T> bool operator<=(nullptr_t, const shared_ptr<T>& b) noexcept; template <class T> bool operator>(const shared_ptr<T>& a, nullptr_t) noexcept; template <class T> bool operator>(nullptr_t, const shared_ptr<T>& b) noexcept; template <class T> bool operator>=(const shared_ptr<T>& a, nullptr_t) noexcept; template <class T> bool operator>=(nullptr_t, const shared_ptr<T>& b) 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> dynamic_pointer_cast(const 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> reinterpret_pointer_cast(const 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); }
Специализации shared_ptr должны быть CopyConstructible, CopyAssignableи LessThanComparable, позволяющие использовать их в стандартных контейнерах. Специализации shared_ptr должны быть контекстно преобразованы в bool, позволяя использовать их в логических выражениях и объявлениях в условиях. Параметр шаблона T из shared_ptr может быть неполным типом.
[ Example:
if (shared_ptr<X> px = dynamic_pointer_cast<X>(py)) {
// do something with px
}
— end example ]
Для целей определения присутствия расы данных, функция - членов должна получать доступ и изменять только shared_ptr и weak_ptr сами объекты , а не объекты , они относятся. Изменения в use_count() не отражают модификации, которые могут привести к гонке данных.
Для целей подпункта [util.smartptr]тип указателя Y* называется compatible with типом указателя, T* когда либо он Y* может быть преобразован в, T* либо Y является U[N] и T есть cv U[].
В определениях конструктора, приведенных ниже, включение shared_from_this with pдля указателя p типа Y*означает, что при Y наличии однозначного и доступного базового класса, который является специализацией enable_shared_from_this, то он remove_cv_t<Y>* должен быть неявно преобразован в, T* и конструктор оценивает оператор:
if (p != nullptr && p->weak_this.expired()) p->weak_this = shared_ptr<remove_cv_t<Y>>(*this, const_cast<remove_cv_t<Y>*>(p));
Присвоение weak_this члену не является атомарным и конфликтует с любым потенциально одновременным доступом к тому же объекту ([intro.multithread]).
constexpr shared_ptr() noexcept;
template<class Y> explicit shared_ptr(Y* p);
Requires: Y должен быть законченным типом. Выражение delete[] p, когда T является типом массива или delete p, когда T не является типом массива, должно иметь четко определенное поведение и не должно вызывать исключений.
Effects: Когда T не является типом массива, создает shared_ptr объект, которому принадлежит указатель p. В противном случае создает объект- shared_ptr владелец p и вызывающий объект удаления неопределенного типа delete[] p. Когда T не является типом массива, включается shared_from_this с помощью p. Если выбрасывается исключение, вызывается, delete p если T он не является типом массива, в delete[] p противном случае.
Remarks: Когда T является типом массива, этот конструктор не должен участвовать в разрешении перегрузки, если выражение не delete[] p имеет правильного формата и либо T является U[N] и Y(*)[N] может быть преобразовано в T*, либо T является U[] и Y(*)[] может быть преобразовано в T*. Когда T не является типом массива, этот конструктор не должен участвовать в разрешении перегрузки, если выражение не delete p имеет правильного формата и не Y* может быть преобразовано в T*.
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);
Requires: Создание d и удаление типа, D инициализированного с помощью std::move(d) , не должны вызывать исключений. Выражение d(p) должно иметь четко определенное поведение и не должно вызывать исключений. A должен быть распределителем ([allocator.requirements]).
Effects: Создает shared_ptr объект, которому принадлежит объект p и средство удаления d. Когда T это не массив, первый и второй конструкторы активируются shared_from_this с помощью p. Второй и четвертый конструкторы должны использовать копию a для выделения памяти для внутреннего использования. Если выбрасывается исключение, d(p) вызывается.
Remarks: Когда T это тип массива, этот конструктор не будет участвовать в разрешении перегрузки , если is_move_constructible_v<D> нет true, то выражение d(p) хорошо сформирован, и либо T это U[N] и Y(*)[N] превращена в T*или T вне U[] и Y(*)[] конвертируется в T*. Когда T это не тип массива, этот конструктор не должен участвовать в разрешении перегрузки , если is_move_constructible_v<D> не trueвыражение d(p) хорошо сформировано, и Y* конвертируются в T*.
template<class Y> shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept;
[ Note: Чтобы избежать возможности появления висячего указателя, пользователь этого конструктора должен убедиться, что он p остается действительным, по крайней мере, до тех пор, пока группа владения не r будет уничтожена. ] — end note
[ Note: Этот конструктор позволяет создавать пустой shared_ptr экземпляр с сохраненным указателем, отличным от NULL. ] — end note
shared_ptr(const shared_ptr& r) noexcept;
template<class Y> shared_ptr(const shared_ptr<Y>& r) noexcept;
Remarks: Второй конструктор не должен участвовать в разрешении перегрузки, если он Y* не совместим с T*.
Effects: Если r пусто, создает пустой shared_ptr объект; в противном случае создает shared_ptr объект, с которым совместно владеет r.
shared_ptr(shared_ptr&& r) noexcept;
template<class Y> shared_ptr(shared_ptr<Y>&& r) noexcept;
Remarks: Второй конструктор не должен участвовать в разрешении перегрузки, если он Y* не совместим с T*.
template<class Y> explicit shared_ptr(const weak_ptr<Y>& r);
Effects: Создает shared_ptr объект, который разделяет владение r и хранит копию указателя, хранящегося в r. Если выбрасывается исключение, конструктор не действует.
Remarks: Этот конструктор не должен участвовать в разрешении перегрузки, если он Y* не совместим с T*.
template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
Remarks: Этот конструктор не должен участвовать в разрешении перегрузки , если Y* не совместим с T* и unique_ptr<Y, D>::pointer конвертируется в element_type*.
Effects: Если r.get() == nullptrэквивалентно shared_ptr(). В противном случае, если D это не ссылочный тип, эквивалентный shared_ptr(r.release(), r.get_deleter()). В противном случае эквивалентно shared_ptr(r.release(), ref(r.get_deleter())). Если выбрасывается исключение, конструктор не действует.
~shared_ptr();
[ Note: Так как уничтожение *this уменьшает количество экземпляров, которые разделяют владение, *this на единицу, после того, как *this было уничтожено, все shared_ptr экземпляры, с которыми совместно владеют, *this будут сообщать, use_count() что на единицу меньше его предыдущего значения. ] — end note
shared_ptr& operator=(const shared_ptr& r) noexcept;
template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) noexcept;
[ Note: Обновления счетчика использования, вызванные созданием и разрушением временного объекта, не являются наблюдаемыми побочными эффектами, поэтому реализация может соответствовать эффектам (и подразумеваемым гарантиям) с помощью различных средств, без создания временного. В частности, в примере:
shared_ptr<int> p(new int); shared_ptr<void> q(p); p = p; q = p;
оба назначения могут быть запретными. ] — end note
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;
Remarks: Когда T является типом массива или cv void, не указано, объявлена ли эта функция-член. Если он объявлен, то не указывается, каков его возвращаемый тип, за исключением того, что объявление (хотя и не обязательно определение) функции должно быть правильно сформировано.
T* operator->() const noexcept;
Remarks: Когда T это тип массива, не указывается, объявлена ли эта функция-член. Если он объявлен, то не указывается, каков его возвращаемый тип, за исключением того, что объявление (хотя и не обязательно определение) функции должно быть правильно сформировано.
element_type& operator[](ptrdiff_t i) const;
Remarks: Когда T не является типом массива, не указывается, объявлена ли эта функция-член. Если он объявлен, то не указывается, каков его возвращаемый тип, за исключением того, что объявление (хотя и не обязательно определение) функции должно быть правильно сформировано.
long use_count() const noexcept;
Returns: Количество включенных shared_ptr объектов, *this которым принадлежит общая собственность *this, или 0 когда *this оно пусто.
[ Note: get() == nullptr не подразумевает конкретного возвращаемого значения use_count(). ] — end note
[ Note: weak_ptr<T>::lock() может повлиять на возвращаемое значение use_count(). ] — end note
[ Note: Если несколько потоков могут повлиять на возвращаемое значение use_count(), результат следует рассматривать как приблизительный. В частности, use_count() == 1 это не означает, что доступ через ранее уничтоженный объект shared_ptr в каком-либо смысле завершен. ] — end note
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;
Returns: Неуказанное значение такое, что
x.owner_before(y) определяет строгий слабый порядок, как определено в [alg.sorting];
по отношению эквивалентности , определенное owner_before, !a.owner_before(b) && !b.owner_before(a)два shared_ptr или weak_ptr экземпляры эквивалентны тогда и только тогда , когда они имеют право собственности или являются пустыми.
template<class T, class... Args>
shared_ptr<T> make_shared(Args&&... args);
template<class T, class A, class... Args>
shared_ptr<T> allocate_shared(const A& a, Args&&... args);
Effects: Выделяет память, подходящую для объекта типа, T и создает объект в этой памяти через размещение new-expression ::new (pv) T(std::forward<Args>(args)...). В шаблоне для выделения памяти allocate_shared используется копия a . Если выбрасывается исключение, функции не действуют.
Remarks: shared_ptr Конструктор вызывается этой функции позволяет shared_from_this с адресом создаваемого объекта типа T. Реализации должны выполнять не более одного распределения памяти. [ Note: Это обеспечивает эффективность, эквивалентную навязчивому интеллектуальному указателю. ] — end note
template<class T, class U>
bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
template<class T, class U>
bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
[ Note: Определение функции сравнения позволяет использовать shared_ptr объекты в качестве ключей в ассоциативных контейнерах. ] — end note
template <class T>
bool operator==(const shared_ptr<T>& a, nullptr_t) noexcept;
template <class T>
bool operator==(nullptr_t, const shared_ptr<T>& a) noexcept;
template <class T>
bool operator!=(const shared_ptr<T>& a, nullptr_t) noexcept;
template <class T>
bool operator!=(nullptr_t, const shared_ptr<T>& a) noexcept;
template <class T>
bool operator<(const shared_ptr<T>& a, nullptr_t) noexcept;
template <class T>
bool operator<(nullptr_t, const shared_ptr<T>& a) noexcept;
Returns: Первый шаблон функции возвращается less<shared_ptr<T>::element_type*>()(a.get(), nullptr). Второй шаблон функции возвращается less<shared_ptr<T>::element_type*>()(nullptr, a.get()).
template <class T>
bool operator>(const shared_ptr<T>& a, nullptr_t) noexcept;
template <class T>
bool operator>(nullptr_t, const shared_ptr<T>& a) noexcept;
Returns: Первый шаблон функции возвращается nullptr < a. Второй шаблон функции возвращается a < nullptr.
template <class T>
bool operator<=(const shared_ptr<T>& a, nullptr_t) noexcept;
template <class T>
bool operator<=(nullptr_t, const shared_ptr<T>& a) noexcept;
Returns: Первый шаблон функции возвращается !(nullptr < a). Второй шаблон функции возвращается !(a < nullptr).
template <class T>
bool operator>=(const shared_ptr<T>& a, nullptr_t) noexcept;
template <class T>
bool operator>=(nullptr_t, const shared_ptr<T>& a) noexcept;
template<class T>
void swap(shared_ptr<T>& a, shared_ptr<T>& b) noexcept;
template<class T, class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept;
[ Note: Казалось бы, эквивалентное выражение в shared_ptr<T>(static_cast<T*>(r.get())) конечном итоге приведет к неопределенному поведению, пытаясь дважды удалить один и тот же объект. ] — end note
template<class T, class U>
shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r) noexcept;
Requires: Выражение dynamic_cast<T*>((U*)0) должно быть правильно сформировано и иметь четко определенное поведение.
[ Note: Казалось бы, эквивалентное выражение в shared_ptr<T>(dynamic_cast<T*>(r.get())) конечном итоге приведет к неопределенному поведению, пытаясь дважды удалить один и тот же объект. ] — end note
template<class T, class U>
shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r) noexcept;
[ Note: Казалось бы, эквивалентное выражение в shared_ptr<T>(const_cast<T*>(r.get())) конечном итоге приведет к неопределенному поведению, пытаясь дважды удалить один и тот же объект. ] — end note
template<class T, class U>
shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<U>& r) noexcept;
template<class D, class T>
D* get_deleter(const shared_ptr<T>& p) noexcept;
Returns: Если p владеет средством удаления d типа cv-unqualified D, возвращается addressof(d); в противном случае возвращается nullptr. Возвращенный указатель остается действительным, пока существует shared_ptr экземпляр, которому он принадлежит d. [ Note: Не указано, остается ли указатель действительным дольше этого срока. Это может произойти, если реализация не уничтожит средство удаления до тех пор, пока не будут уничтожены все weak_ptr экземпляры, которые совместноp владеют правами собственности . ] — end note
template<class E, class T, class Y>
basic_ostream<E, T>& operator<< (basic_ostream<E, T>& os, const shared_ptr<Y>& p);