23 General utilities library [utilities]

23.11 Smart pointers [smartptr]

23.11.1 Class template unique_­ptr [unique.ptr]

A unique pointer - это объект, который владеет другим объектом и управляет этим другим объектом с помощью указателя. Точнее, уникальный указатель - это объект, u который хранит указатель на второй объект p и будет удален, p когда u сам будет уничтожен (например, при выходе из области видимости блока ([stmt.dcl])). В этом контексте u говорят own p.

Механизм , с помощью которого u распоряжается p известно как p«ы связаны deleter, функциональный объект , чей правильный вызов приводит к p» с соответствующим расположением ( как правило , его удаление).

Пусть обозначение u.p обозначает указатель, хранящийся в u, и пусть u.d обозначает связанный с ним удалитель. По запросу u может reset (заменить) u.p и u.d другим указателем и средством удаления, но должен должным образом удалить принадлежащий ему объект с помощью связанного средства удаления, прежде чем такая замена будет считаться завершенной.

Дополнительно u может по запросу transfer ownership на другой уникальный указатель u2. По завершении такой передачи выполняются следующие постусловия:

  • u2.p равно предварительной передаче u.p,

  • u.p равно nullptr, и

  • если u.d состояние сохранялось до передачи , такое состояние было переведено в u2.d.

Как и в случае сброса, он u2 должен должным образом избавиться от объекта, принадлежащего ему до передачи, через связанный с ним удалитель до передачи, прежде чем передача права собственности будет считаться завершенной. [ Note: Состояние удалителя никогда не нужно копировать, его нужно только перемещать или менять местами по мере передачи права собственности. ] end note

Каждый объект типа, U созданный из unique_­ptr шаблона, указанного в этом подпункте, имеет строгую семантику владения уникальным указателем, указанную выше. В частичном удовлетворении этой семантики каждое такое U есть MoveConstructible и MoveAssignable, но не является CopyConstructible ни CopyAssignable. Параметр шаблона T из unique_­ptr может быть неполным типом.

[ Note: Использование unique_­ptr включает обеспечение безопасности исключений для динамически выделяемой памяти, передачу права собственности на динамически выделяемую память функции и возврат динамически выделенной памяти из функции. ] end note

namespace std {
  template<class T> struct default_delete;
  template<class T> struct default_delete<T[]>;

  template<class T, class D = default_delete<T>> class unique_ptr;
  template<class T, class D> class unique_ptr<T[], D>;

  template<class T, class... Args> unique_ptr<T> make_unique(Args&&... args);
  template<class T> unique_ptr<T> make_unique(size_t n);
  template<class T, class... Args> unspecified make_unique(Args&&...) = delete;

  template<class T, class D> void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) noexcept;

  template<class T1, class D1, class T2, class D2>
    bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template<class T1, class D1, class T2, class D2>
    bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template<class T1, class D1, class T2, class D2>
    bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template<class T1, class D1, class T2, class D2>
    bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template<class T1, class D1, class T2, class D2>
    bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template<class T1, class D1, class T2, class D2>
    bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);

  template <class T, class D>
    bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept;
  template <class T, class D>
    bool operator==(nullptr_t, const unique_ptr<T, D>& y) noexcept;
  template <class T, class D>
    bool operator!=(const unique_ptr<T, D>& x, nullptr_t) noexcept;
  template <class T, class D>
    bool operator!=(nullptr_t, const unique_ptr<T, D>& y) noexcept;
  template <class T, class D>
    bool operator<(const unique_ptr<T, D>& x, nullptr_t);
  template <class T, class D>
    bool operator<(nullptr_t, const unique_ptr<T, D>& y);
  template <class T, class D>
    bool operator<=(const unique_ptr<T, D>& x, nullptr_t);
  template <class T, class D>
    bool operator<=(nullptr_t, const unique_ptr<T, D>& y);
  template <class T, class D>
    bool operator>(const unique_ptr<T, D>& x, nullptr_t);
  template <class T, class D>
    bool operator>(nullptr_t, const unique_ptr<T, D>& y);
  template <class T, class D>
    bool operator>=(const unique_ptr<T, D>& x, nullptr_t);
  template <class T, class D>
    bool operator>=(nullptr_t, const unique_ptr<T, D>& y);

}

23.11.1.1 Default deleters [unique.ptr.dltr]

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

Шаблон класса default_­delete служит средством удаления (политика уничтожения) по умолчанию для шаблона класса unique_­ptr.

Параметр шаблона T из default_­delete может быть неполным типом.

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

namespace std {
  template <class T> struct default_delete {
    constexpr default_delete() noexcept = default;
    template <class U> default_delete(const default_delete<U>&) noexcept;
    void operator()(T*) const;
  };
}

template <class U> default_delete(const default_delete<U>& other) noexcept;

Effects: Создает default_­delete объект из другого default_­delete<U> объекта.

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки, если он не U* может быть неявно преобразован в T*.

void operator()(T* ptr) const;

Effects: Вызовы delete на ptr.

Remarks: Если T это неполный тип, программа плохо сформирована.

23.11.1.1.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> default_delete(const default_delete<U[]>&) noexcept;
    template <class U> void operator()(U* ptr) const;
  };
}

template <class U> default_delete(const default_delete<U[]>& other) noexcept;

Effects: создает default_­delete объект из другого default_­delete<U[]> объекта.

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки, если он не U(*)[] может быть преобразован в T(*)[].

template <class U> void operator()(U* ptr) const;

Effects: Вызовы delete[] на ptr.

Remarks: Если U это неполный тип, программа плохо сформирована. Эта функция не должна участвовать в разрешении перегрузки, если U(*)[] она не может быть преобразована в T(*)[].

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

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;
    explicit unique_ptr(pointer p) noexcept;
    unique_ptr(pointer p, see below d1) noexcept;
    unique_ptr(pointer p, see below d2) noexcept;
    unique_ptr(unique_ptr&& u) noexcept;
    constexpr unique_ptr(nullptr_t) noexcept;
    template <class U, class E>
      unique_ptr(unique_ptr<U, E>&& u) noexcept;

    // [unique.ptr.single.dtor], destructor
    ~unique_ptr();

    // [unique.ptr.single.asgn], assignment
    unique_ptr& operator=(unique_ptr&& u) noexcept;
    template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
    unique_ptr& operator=(nullptr_t) noexcept;

    // [unique.ptr.single.observers], observers
    add_lvalue_reference_t<T> operator*() const;
    pointer operator->() const noexcept;
    pointer get() const noexcept;
    deleter_type& get_deleter() noexcept;
    const deleter_type& get_deleter() const noexcept;
    explicit operator bool() const noexcept;

    // [unique.ptr.single.modifiers], modifiers
    pointer release() noexcept;
    void reset(pointer p = pointer()) noexcept;
    void swap(unique_ptr& u) noexcept;

    // disable copy from lvalue
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;
  };
}

Тип по умолчанию для параметра шаблона D - default_­delete. Аргумент шаблона, предоставляемый клиентом, D должен быть function object typeссылкой lvalue на функцию или ссылкой lvalue на тип объекта функции, для которого, учитывая значение d типа D и значение ptr типа unique_­ptr<T, D>​::​pointer, выражение d(ptr) является действительным и имеет эффект удаления указателя как подходит для этого удалителя.

Если тип удалителя D не является ссылочным типом, он D должен удовлетворять требованиям Destructible.

Если qualified-id remove_­reference_­t<D>​::​pointer действительно и обозначает тип ([temp.deduct]), то unique_­ptr<T, D>​::​pointer должно быть синонимом для remove_­reference_­t<D>​::​pointer. В противном случае unique_­ptr<T, D>​::​pointer будет синонимом element_­type*. Тип unique_­ptr<T, D>​::​pointer должен удовлетворять требованиям NullablePointer.

[ Example: Принимая во внимание тип распределителя X ([allocator.requirements]) и позволяя A быть синонимом allocator_­traits<X>, типов A​::​pointer, A​::​const_­pointer, A​::​void_­pointerи A​::​const_­void_­pointer могут быть использованы в качестве unique_­ptr<T, D>​::​pointer. ] end example

23.11.1.2.1 unique_­ptr constructors [unique.ptr.single.ctor]

constexpr unique_ptr() noexcept; constexpr unique_ptr(nullptr_t) noexcept;

Requires: D должны удовлетворять требованиям DefaultConstructible, и эта конструкция не должна вызывать исключения.

Effects: Создает unique_­ptr объект, который ничего не владеет, инициализируя значение сохраненного указателя и сохраненного средства удаления.

Postconditions: get() == nullptr. get_­deleter() возвращает ссылку на сохраненный удалитель.

Remarks: Если is_­pointer_­v<deleter_­type> есть true или is_­default_­constructible_­v<deleter_­type> есть false, этот конструктор не должен участвовать в разрешении перегрузки.

explicit unique_ptr(pointer p) noexcept;

Requires: D должны удовлетворять требованиям DefaultConstructible, и эта конструкция не должна вызывать исключения.

Effects: Создает объект, unique_­ptr который владеет p, инициализируя сохраненный указатель p и инициализируя значение сохраненного средства удаления.

Postconditions: get() == p. get_­deleter() возвращает ссылку на сохраненный удалитель.

Remarks: Если is_­pointer_­v<deleter_­type> есть true или is_­default_­constructible_­v<deleter_­type> есть false, этот конструктор не должен участвовать в разрешении перегрузки. Если deduction ([over.match.class.deduct]) аргумента шаблона класса выберет шаблон функции, соответствующий этому конструктору, то программа сформирована неправильно.

unique_ptr(pointer p, see below d1) noexcept; unique_ptr(pointer p, see below d2) noexcept;

Подпись этих конструкторов зависит от того, D является ли это ссылочным типом. Если D это не ссылочный тип A, то подписи:

unique_ptr(pointer p, const A& d) noexcept;
unique_ptr(pointer p, A&& d) noexcept;

Если D это ссылочный тип lvalue A&, то подписи будут следующими:

unique_ptr(pointer p, A& d) noexcept;
unique_ptr(pointer p, A&& d) = delete;

Если D это ссылочный тип lvalue const A&, то подписи будут следующими:

unique_ptr(pointer p, const A& d) noexcept;
unique_ptr(pointer p, const A&& d) = delete;

Effects: Создает unique_­ptr объект, которому принадлежит p, инициализируя сохраненный указатель p и инициализируя средство удаления из std​::​forward<decltype(d)>(d).

Remarks: Эти конструкторы не должны участвовать в разрешении перегрузки , если is_­constructible_­v<D, decltype(d)> не true.

Postconditions: get() == p. get_­deleter() возвращает ссылку на сохраненный удалитель. Если D является ссылочным типом, get_­deleter() возвращает ссылку на lvalue d.

Remarks: Если аргумент deduction ([over.match.class.deduct]) шаблона класса выберет шаблон функции, соответствующий любому из этих конструкторов, то программа сформирована неправильно.

[Example:

D d;
unique_ptr<int, D> p1(new int, D());        // D must be MoveConstructible
unique_ptr<int, D> p2(new int, d);          // D must be CopyConstructible
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]

unique_ptr(unique_ptr&& u) noexcept;

Requires: Если D не является эталонным типом, он D должен удовлетворять требованиям MoveConstructible. Построение удалителя из rvalue типа D не должно вызывать исключения.

Effects: Создает unique_­ptr путем передачи права собственности от u к *this. Если D это ссылочный тип, это средство удаления является копией, созданной из средства uудаления; в противном случае этот удалитель uсоздается на основе удалителя. [ Note: Конструктор удаления может быть реализован с помощью std​::​forward<D>. ] end note

Postconditions: get() дает значение, u.get() полученное до строительства. get_­deleter() возвращает ссылку на сохраненный удалитель, созданный из u.get_­deleter(). Если D это ссылочный тип, то оба ссылаются на одинget_­deleter() и u.get_­deleter() тот же удалитель lvalue.

template <class U, class E> unique_ptr(unique_ptr<U, E>&& u) noexcept;

Requires: Если E это не ссылочный тип, построение удалителя из rvalue типа E должно быть правильно сформировано и не должно вызывать исключения. В противном случае E является ссылочным типом, и конструкция удалителя из lvalue типа E должна быть правильно сформирована и не должна вызывать исключения.

Remarks: Этот конструктор не должен участвовать в разрешении перегрузки, если:

  • unique_­ptr<U, E>​::​pointer неявно конвертируется в pointer,

  • U не является типом массива и

  • либо D является ссылочным типом и E относится к тому же типу D, либо D не является ссылочным типом и E может неявно преобразовываться в D.

Effects: Создает unique_­ptr путем передачи права собственности от u к *this. Если E это ссылочный тип, это средство удаления является копией, созданной из средства uудаления; в противном случае этот удалитель uсоздается на основе удалителя. [ Note: Конструктор удаления может быть реализован с помощью std​::​forward<E>. ] end note

Postconditions: get() дает значение, u.get() полученное до строительства. get_­deleter() возвращает ссылку на сохраненный удалитель, созданный из u.get_­deleter().

23.11.1.2.2 unique_­ptr destructor [unique.ptr.single.dtor]

~unique_ptr();

Requires: Выражение get_­deleter()(get()) должно быть правильно сформировано, иметь четко определенное поведение и не должно вызывать исключений. [ Note: Использование default_­delete требует T полного типа. ]end note

Effects: Если get() == nullptr нет эффектов. В противном случае get_­deleter()(get()).

23.11.1.2.3 unique_­ptr assignment [unique.ptr.single.asgn]

unique_ptr& operator=(unique_ptr&& u) noexcept;

Requires: Если D не является ссылочным типом, он D должен удовлетворять требованиям, MoveAssignable и назначение удалителя из rvalue типа D не должно вызывать исключения. В противном случае D - ссылочный тип; remove_­reference_­t<D> должен удовлетворять CopyAssignable требованиям, и назначение удалителя из lvalue типа D не должно вызывать исключения.

Effects: Передает право собственности от u к, *this как если бы при звонке с reset(u.release()) последующим get_­deleter() = std​::​forward<D>(u.get_­deleter()).

Returns: *this.

template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;

Requires: Если E это не ссылочный тип, назначение удалителя из rvalue типа E должно быть правильно сформированным и не должно вызывать исключения. В противном случае E - это ссылочный тип, и назначение удалителя из lvalue типа E должно быть правильно сформированным и не должно вызывать исключения.

Remarks: Этот оператор не должен участвовать в разрешении перегрузки, если:

  • unique_­ptr<U, E>​::​pointer неявно конвертируется в pointer, и

  • U не является типом массива и

  • is_­assignable_­v<D&, E&&> есть true.

Effects: Передает право собственности от u к, *this как если бы при звонке с reset(u.release()) последующим get_­deleter() = std​::​forward<E>(u.get_­deleter()).

Returns: *this.

unique_ptr& operator=(nullptr_t) noexcept;

Effects: Как будто мимо reset().

Postconditions: get() == nullptr.

Returns: *this.

23.11.1.2.4 unique_­ptr observers [unique.ptr.single.observers]

add_lvalue_reference_t<T> operator*() const;

Requires: get() != nullptr.

Returns: *get().

pointer operator->() const noexcept;

Requires: get() != nullptr.

Returns: get().

[ Note: Для использования этой функции обычно требуется T полный тип. ] end note

pointer get() const noexcept;

Returns: Сохраненный указатель.

deleter_type& get_deleter() noexcept; const deleter_type& get_deleter() const noexcept;

Returns: Ссылка на сохраненный удалитель.

explicit operator bool() const noexcept;

Returns: get() != nullptr.

23.11.1.2.5 unique_­ptr modifiers [unique.ptr.single.modifiers]

pointer release() noexcept;

Postconditions: get() == nullptr.

Returns: Значение get() было в начале вызова release.

void reset(pointer p = pointer()) noexcept;

Requires: Выражение get_­deleter()(get()) должно быть правильно сформировано, иметь четко определенное поведение и не должно вызывать исключений.

Effects: Присваивается p сохраненному указателю, и затем, если и только если старое значение сохраненного указателя, old_­pне было равно nullptr, вызывает get_­deleter()(old_­p). [ Note: Порядок этих операций важен, потому что вызов get_­deleter() может уничтожить *this. ] end note

Postconditions: get() == p. [ Note: Постусловие не выполняется, если вызов get_­deleter() уничтожает, *this поскольку this->get() больше не является допустимым выражением. ] end note

void swap(unique_ptr& u) noexcept;

Requires: get_­deleter() должно бытьswappable и не должно вызывать исключение swap.

Effects: Вызывает swap сохраненные указатели и сохраненные удалители *this и u.

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

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> explicit unique_ptr(U p) noexcept;
    template <class U> unique_ptr(U p, see below d) noexcept;
    template <class U> unique_ptr(U p, see below d) noexcept;
    unique_ptr(unique_ptr&& u) noexcept;
    template <class U, class E>
      unique_ptr(unique_ptr<U, E>&& u) noexcept;
    constexpr unique_ptr(nullptr_t) noexcept;

    // destructor
    ~unique_ptr();

    // assignment
    unique_ptr& operator=(unique_ptr&& u) noexcept;
    template <class U, class E>
      unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
    unique_ptr& operator=(nullptr_t) noexcept;

    // [unique.ptr.runtime.observers], observers
    T& operator[](size_t i) const;
    pointer get() const noexcept;
    deleter_type& get_deleter() noexcept;
    const deleter_type& get_deleter() const noexcept;
    explicit operator bool() const noexcept;

    // [unique.ptr.runtime.modifiers], modifiers
    pointer release() noexcept;
    template <class U> void reset(U p) noexcept;
    void reset(nullptr_t = nullptr) noexcept;
    void swap(unique_ptr& u) noexcept;

    // disable copy from lvalue
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;
  };
}

Специализация для типов массивов предоставляется с немного измененным интерфейсом.

  • Преобразования между различными типами, unique_­ptr<T[], D> которые были бы запрещены для соответствующих типов указателей на массив, и преобразования в или из формunique_­ptr, не являющихся массивами , создают плохо сформированную программу.

  • Указатели на типы, производные от T , отклоняются конструкторами и reset.

  • Наблюдатели так operator* и operator-> не предусмотрены.

  • Предусмотрен обозреватель индексации operator[] .

  • Будет звонить средство удаления по умолчанию delete[].

Ниже приведены описания только для членов, которые отличаются от основного шаблона.

Аргумент шаблона T должен быть полного типа.

23.11.1.3.1 unique_­ptr constructors [unique.ptr.runtime.ctor]

template <class U> explicit unique_ptr(U p) noexcept;

Этот конструктор ведет себя так же, как конструктор в основном шаблоне, который принимает единственный параметр типа, pointer за исключением того, что он дополнительно не должен участвовать в разрешении перегрузки, если только

  • U того же типа, что и pointer, или

  • pointer имеет тот же тип element_­type*, U что и тип указателя V*, и V(*)[] может быть преобразован в element_­type(*)[].

template <class U> unique_ptr(U p, see below d) noexcept; template <class U> unique_ptr(U p, see below d) noexcept;

Эти конструкторы ведут себя так же, как конструкторы в основном шаблоне, которые принимают параметр типа pointer и второй параметр, за исключением того, что они не должны участвовать в разрешении перегрузки, если либо

  • U того же типа, что и pointer,

  • U есть nullptr_­t, или

  • pointer имеет тот же тип element_­type*, U что и тип указателя V*, и V(*)[] может быть преобразован в element_­type(*)[].

template <class U, class E> unique_ptr(unique_ptr<U, E>&& u) noexcept;

Этот конструктор ведет себя так же , как в первичном шаблоне, за исключением того, что она не будет участвовать в разрешении перегрузки , если все из следующих условий не выполняется, где UP находится unique_­ptr<U, E>:

  • U - это тип массива, а

  • pointer того же типа element_­type*, что и, и

  • UP​::​pointer того же типа UP​::​element_­type*, что и, и

  • UP​::​element_­type(*)[] конвертируется в element_­type(*)[], и

  • либо D является ссылочным типом и E относится к тому же типу D, либо D не является ссылочным типом и E может неявно преобразовываться в D.

[ Note: Это заменяет спецификацию разрешения перегрузки основного шаблона ] end note

23.11.1.3.2 unique_­ptr assignment [unique.ptr.runtime.asgn]

template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u)noexcept;

Этот оператор ведет себя так же , как в первичном шаблоне, за исключением того, что она не будет участвовать в разрешении перегрузки , если все из следующих условий не выполняется, где UP находится unique_­ptr<U, E>:

  • U - это тип массива, а

  • pointer того же типа element_­type*, что и, и

  • UP​::​pointer того же типа UP​::​element_­type*, что и, и

  • UP​::​element_­type(*)[] конвертируется в element_­type(*)[], и

  • is_­assignable_­v<D&, E&&> есть true.

[ Note: Это заменяет спецификацию разрешения перегрузки основного шаблона ] end note

23.11.1.3.3 unique_­ptr observers [unique.ptr.runtime.observers]

T& operator[](size_t i) const;

Requires: i < количество элементов в массиве, на которые указывает сохраненный указатель.

Returns: get()[i].

23.11.1.3.4 unique_­ptr modifiers [unique.ptr.runtime.modifiers]

void reset(nullptr_t p = nullptr) noexcept;

Effects: Эквивалентно reset(pointer()).

template <class U> void reset(U p) noexcept;

Эта функция ведет себя так же, как reset член основного шаблона, за исключением того, что она не должна участвовать в разрешении перегрузки, если либо

  • U того же типа, что и pointer, или

  • pointer имеет тот же тип element_­type*, U что и тип указателя V*, и V(*)[] может быть преобразован в element_­type(*)[].

23.11.1.4 unique_­ptr creation [unique.ptr.create]

template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);

Remarks: Эта функция не должна участвовать в разрешении перегрузки, если T она не является массивом.

Returns: unique_­ptr<T>(new T(std​::​forward<Args>(args)...)).

template <class T> unique_ptr<T> make_unique(size_t n);

Remarks: Эта функция не должна участвовать в разрешении перегрузки, если только T это не массив с неизвестной границей.

Returns: unique_­ptr<T>(new remove_­extent_­t<T>[n]()).

template <class T, class... Args> unspecified make_unique(Args&&...) = delete;

Remarks: Эта функция не должна участвовать в разрешении перегрузки, если только T это не массив с известными границами.

23.11.1.5 unique_­ptr specialized algorithms [unique.ptr.special]

template <class T, class D> void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) noexcept;

Remarks: Эта функция не будет участвовать в разрешении перегрузки , если is_­swappable_­v<D> не true.

Effects: Звонки x.swap(y).

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.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: 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);

Requires: Пусть CT обозначают

common_type_t<typename unique_ptr<T1, D1>::pointer,
              typename unique_ptr<T2, D2>::pointer>

Тогда специализация less<CT> должна быть a, function object type которая индуцирует a strict weak ordering для значений указателя.

Returns: less<CT>()(x.get(), y.get()).

Remarks: Если unique_­ptr<T1, D1>​::​pointer не может быть неявно преобразован CT или unique_­ptr<T2, D2>​::​pointer неявно преобразован в CT, программа имеет неправильный формат.

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 T, class D> bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator==(nullptr_t, const unique_ptr<T, D>& x) noexcept;

Returns: !x.

template <class T, class D> bool operator!=(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator!=(nullptr_t, const unique_ptr<T, D>& x) noexcept;

Returns: (bool)x.

template <class T, class D> bool operator<(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator<(nullptr_t, const unique_ptr<T, D>& x);

Requires: Специализация less<unique_­ptr<T, D>​::​pointer> должна быть a, function object type которая индуцирует a strict weak ordering для значений указателя.

Returns: Первый шаблон функции возвращается less<unique_­ptr<T, D>​::​pointer>()(x.get(),
nullptr)
. Второй шаблон функции возвращается less<unique_­ptr<T, D>​::​pointer>()(nullptr, x.get()).

template <class T, class D> bool operator>(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>(nullptr_t, const unique_ptr<T, D>& x);

Returns: Первый шаблон функции возвращается nullptr < x. Второй шаблон функции возвращается x < nullptr.

template <class T, class D> bool operator<=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator<=(nullptr_t, const unique_ptr<T, D>& x);

Returns: Первый шаблон функции возвращается !(nullptr < x). Второй шаблон функции возвращается !(x < nullptr).

template <class T, class D> bool operator>=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>=(nullptr_t, const unique_ptr<T, D>& x);

Returns: Первый шаблон функции возвращается !(x < nullptr). Второй шаблон функции возвращается !(nullptr < x).

23.11.2 Shared-ownership pointers [util.smartptr]

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

namespace std {
  class bad_weak_ptr : public exception {
  public:
    bad_weak_ptr() noexcept;
  };
}

Исключение типа bad_­weak_­ptr выбрасывается в shared_­ptr конструктор , принимающий weak_­ptr.

bad_weak_ptr() noexcept;

Postconditions: what() возвращает определяемый реализацией файл ntbs .

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

В 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[].

23.11.2.2.1 shared_­ptr constructors [util.smartptr.shared.const]

В определениях конструктора, приведенных ниже, включение 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;

Effects: Создает пустой shared_­ptr объект.

Postconditions: use_­count() == 0 && get() == nullptr.

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 противном случае.

Postconditions: use_­count() == 1 && get() == p.

Throws: bad_­allocили исключение, определяемое реализацией, когда не удалось получить ресурс, отличный от памяти.

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) вызывается.

Postconditions: use_­count() == 1 && get() == p.

Throws: bad_­allocили исключение, определяемое реализацией, когда не удалось получить ресурс, отличный от памяти.

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;

Effects: Создает shared_­ptr экземпляр, который хранит p и разделяет владение r.

Postconditions: get() == p && use_­count() == r.use_­count().

[ 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.

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;

Remarks: Второй конструктор не должен участвовать в разрешении перегрузки, если он Y* не совместим с T*.

Effects: Move создает shared_­ptr экземпляр из r.

Postconditions: *this должен содержать старое значение r. r будет пустым. r.get() == nullptr.

template<class Y> explicit shared_ptr(const weak_ptr<Y>& r);

Effects: Создает shared_­ptr объект, который разделяет владение r и хранит копию указателя, хранящегося в r. Если выбрасывается исключение, конструктор не действует.

Postconditions: use_­count() == r.use_­count().

Throws: bad_­weak_­ptr когда r.expired().

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())). Если выбрасывается исключение, конструктор не действует.

23.11.2.2.2 shared_­ptr destructor [util.smartptr.shared.dest]

~shared_ptr();

Effects:

  • Если *this он пуст или принадлежит другому shared_­ptr экземпляру (use_­count() > 1), побочных эффектов нет.

  • В противном случае, если *this владелец объекта p и Deleter d, d(p) называется.

  • В противном случае *this владеет указателем pи delete p вызывается.

[ Note: Так как уничтожение *this уменьшает количество экземпляров, которые разделяют владение, *this на единицу, после того, как *this было уничтожено, все shared_­ptr экземпляры, с которыми совместно владеют, *this будут сообщать, use_­count() что на единицу меньше его предыдущего значения. ] end note

23.11.2.2.3 shared_­ptr 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: Эквивалентно shared_­ptr(r).swap(*this).

Returns: *this.

[ 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;

Effects: Эквивалентно shared_­ptr(std​::​move(r)).swap(*this).

Returns: *this.

template <class Y, class D> shared_ptr& operator=(unique_ptr<Y, D>&& r);

Effects: Эквивалентно shared_­ptr(std​::​move(r)).swap(*this).

Returns: *this.

23.11.2.2.4 shared_­ptr modifiers [util.smartptr.shared.mod]

void swap(shared_ptr& r) noexcept;

Effects: Меняет содержимое *this и r.

void reset() noexcept;

Effects: Эквивалентно shared_­ptr().swap(*this).

template<class Y> void reset(Y* p);

Effects: Эквивалентно shared_­ptr(p).swap(*this).

template<class Y, class D> void reset(Y* p, D d);

Effects: Эквивалентно shared_­ptr(p, d).swap(*this).

template<class Y, class D, class A> void reset(Y* p, D d, A a);

Effects: Эквивалентно shared_­ptr(p, d, a).swap(*this).

23.11.2.2.5 shared_­ptr observers [util.smartptr.shared.obs]

element_type* get() const noexcept;

Returns: Сохраненный указатель.

T& operator*() const noexcept;

Requires: get() != 0.

Returns: *get().

Remarks: Когда T является типом массива или cv void, не указано, объявлена ​​ли эта функция-член. Если он объявлен, то не указывается, каков его возвращаемый тип, за исключением того, что объявление (хотя и не обязательно определение) функции должно быть правильно сформировано.

T* operator->() const noexcept;

Requires: get() != 0.

Returns: get().

Remarks: Когда T это тип массива, не указывается, объявлена ​​ли эта функция-член. Если он объявлен, то не указывается, каков его возвращаемый тип, за исключением того, что объявление (хотя и не обязательно определение) функции должно быть правильно сформировано.

element_type& operator[](ptrdiff_t i) const;

Requires: get() != 0 && i >= 0. Если T есть U[N], то i < N.

Returns: get()[i].

Remarks: Когда T не является типом массива, не указывается, объявлена ​​ли эта функция-член. Если он объявлен, то не указывается, каков его возвращаемый тип, за исключением того, что объявление (хотя и не обязательно определение) функции должно быть правильно сформировано.

Throws: Ничего такого.

long use_count() const noexcept;

Returns: Количество включенных shared_­ptr объектов, *this которым принадлежит общая собственность *this, или 0 когда *this оно пусто.

Synchronization: Никто.

[ 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;

Returns: get() != 0.

template<class U> bool owner_before(const shared_ptr<U>& b) const noexcept; template<class U> bool owner_before(const weak_ptr<U>& b) const noexcept;

Returns: Неуказанное значение такое, что

  • x.owner_­before(y) определяет строгий слабый порядок, как определено в [alg.sorting];

  • по отношению эквивалентности , определенное owner_­before, !a.owner_­before(b) && !b.owner_­before(a)два shared_­ptr или weak_­ptr экземпляры эквивалентны тогда и только тогда , когда они имеют право собственности или являются пустыми.

23.11.2.2.6 shared_­ptr creation [util.smartptr.shared.create]

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);

Requires: Выражение ​::​new (pv) T(std​::​forward<Args>(args)...), где pv имеет тип void* и указывает на хранилище, подходящее для хранения объекта типа T, должно быть правильно сформировано. A должен быть allocator. Конструктор копирования и деструктор A не должны вызывать исключений.

Effects: Выделяет память, подходящую для объекта типа, T и создает объект в этой памяти через размещение new-expression ​::​new (pv) T(std​::​forward<Args>(args)...). В шаблоне для выделения памяти allocate_­shared используется копия a . Если выбрасывается исключение, функции не действуют.

Returns: shared_­ptr Экземпляр , который хранит и владеет адрес создаваемого объекта типа T.

Postconditions: get() != 0 && use_­count() == 1.

Throws: bad_­allocили исключение, A​::​allocate созданное конструктором T.

Remarks: shared_­ptr Конструктор вызывается этой функции позволяет shared_­from_­this с адресом создаваемого объекта типа T. Реализации должны выполнять не более одного распределения памяти. [ Note: Это обеспечивает эффективность, эквивалентную навязчивому интеллектуальному указателю. ] end note

[ Note: Эти функции обычно выделяют больше памяти, чем sizeof(T) позволяют внутренние структуры бухгалтерского учета, такие как счетчик ссылок. ] end note

23.11.2.2.7 shared_­ptr 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, class U> bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;

Returns: less<>()(a.get(), b.get()).

[ 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;

Returns: !a.

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: (bool)a.

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;

Returns: Первый шаблон функции возвращается !(a < nullptr). Второй шаблон функции возвращается !(nullptr < a).

23.11.2.2.8 shared_­ptr specialized algorithms [util.smartptr.shared.spec]

template<class T> void swap(shared_ptr<T>& a, shared_ptr<T>& b) noexcept;

Effects: Эквивалентно a.swap(b).

23.11.2.2.9 shared_­ptr casts [util.smartptr.shared.cast]

template<class T, class U> shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept;

Requires: Выражение static_­cast<T*>((U*)0) должно быть правильным.

Returns:

shared_ptr<T>(r, static_cast<typename shared_ptr<T>::element_type*>(r.get()))

[ 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) должно быть правильно сформировано и иметь четко определенное поведение.

Returns:

  • Когда dynamic_­cast<typename shared_­ptr<T>​::​element_­type*>(r.get()) возвращает значение отличное от нуля p, shared_­ptr<T>(r, p).

  • В противном случае shared_­ptr<T>().

[ 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;

Requires: Выражение const_­cast<T*>((U*)0) должно быть правильным.

Returns:

shared_ptr<T>(r, const_cast<typename shared_ptr<T>::element_type*>(r.get()))

[ 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;

Requires: Выражение reinterpret_­cast<T*>((U*)0) должно быть правильным.

Returns:

shared_ptr<T>(r, reinterpret_cast<typename shared_ptr<T>::element_type*>(r.get()))

[ Note: Казалось бы, эквивалентное выражение в shared_­ptr<T>(reinterpret_­cast<T*>(r.get())) конечном итоге приведет к неопределенному поведению, пытаясь дважды удалить один и тот же объект. ] end note

23.11.2.2.10 get_­deleter [util.smartptr.getdeleter]

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

23.11.2.2.11 shared_­ptr 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: Как будто по: os << p.get();

Returns: os.

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

В weak_­ptr шаблоне класса хранится слабая ссылка на объект, которым уже управляет shared_­ptr. Для доступа к объекту a weak_­ptr можно преобразовать в a shared_­ptr с помощью функции-члена lock.

namespace std {
  template<class T> class weak_ptr {
  public:
    using element_type = 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;
    template<class U> bool owner_before(const weak_ptr<U>& b) const;
  };

  template<class T> weak_ptr(shared_ptr<T>) -> weak_ptr<T>;


  // [util.smartptr.weak.spec], specialized algorithms
  template<class T> void swap(weak_ptr<T>& a, weak_ptr<T>& b) noexcept;
}

Специализации weak_­ptr должны быть CopyConstructible и CopyAssignable, позволяющие использовать их в стандартных контейнерах. Параметр шаблона T из weak_­ptr может быть неполным типом.

23.11.2.3.1 weak_­ptr constructors [util.smartptr.weak.const]

constexpr weak_ptr() noexcept;

Effects: Создает пустой weak_­ptr объект.

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;

Remarks: Второй и третий конструкторы не должны участвовать в разрешении перегрузки, если они Y* не совместимы с T*.

Effects: Если r пусто, создает пустой weak_­ptr объект; в противном случае создает weak_­ptr объект, который разделяет владение r и хранит копию указателя, хранящегося в r.

Postconditions: use_­count() == r.use_­count().

weak_ptr(weak_ptr&& r) noexcept; template<class Y> weak_ptr(weak_ptr<Y>&& r) noexcept;

Remarks: Второй конструктор не должен участвовать в разрешении перегрузки, если он Y* не совместим с T*.

Effects: Move создает weak_­ptr экземпляр из r.

Postconditions: *this должен содержать старое значение r. r будет пустым. r.use_­count() == 0.

23.11.2.3.2 weak_­ptr destructor [util.smartptr.weak.dest]

~weak_ptr();

Effects: Уничтожает этот weak_­ptr объект, но не влияет на объект, на который указывает его сохраненный указатель.

23.11.2.3.3 weak_­ptr 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: Эквивалентно weak_­ptr(r).swap(*this).

Remarks: Реализация может обеспечить эффекты (и подразумеваемые гарантии) разными способами, не создавая временного.

Returns: *this.

weak_ptr& operator=(weak_ptr&& r) noexcept; template<class Y> weak_ptr& operator=(weak_ptr<Y>&& r) noexcept;

Effects: Эквивалентно weak_­ptr(std​::​move(r)).swap(*this).

Returns: *this.

23.11.2.3.4 weak_­ptr modifiers [util.smartptr.weak.mod]

void swap(weak_ptr& r) noexcept;

Effects: Меняет содержимое *this и r.

void reset() noexcept;

Effects: Эквивалентно weak_­ptr().swap(*this).

23.11.2.3.5 weak_­ptr observers [util.smartptr.weak.obs]

long use_count() const noexcept;

Returns: 0 если *this пусто; в противном случае - количество shared_­ptr экземпляров, с которыми совместно владеют *this.

bool expired() const noexcept;

Returns: use_­count() == 0.

shared_ptr<T> lock() const noexcept;

Returns: expired() ? shared_­ptr<T>() : shared_­ptr<T>(*this), выполняется атомарно.

template<class U> bool owner_before(const shared_ptr<U>& b) const; template<class U> bool owner_before(const weak_ptr<U>& b) const;

Returns: Неуказанное значение такое, что

  • x.owner_­before(y) определяет строгий слабый порядок, как определено в [alg.sorting];

  • по отношению эквивалентности , определенное owner_­before, !a.owner_­before(b) && !b.owner_­before(a)два shared_­ptr или weak_­ptr экземпляры эквивалентны тогда и только тогда , когда они имеют право собственности или являются пустыми.

23.11.2.3.6 weak_­ptr specialized algorithms [util.smartptr.weak.spec]

template<class T> void swap(weak_ptr<T>& a, weak_ptr<T>& b) noexcept;

Effects: Эквивалентно a.swap(b).

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

Шаблон класса owner_­less позволяет смешанное сравнение общих и слабых указателей на основе владения.

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) вернусь x.owner_­before(y). [ Note: Обратите внимание, что

  • operator() определяет строгий слабый порядок, как определено в [alg.sorting];

  • по отношению эквивалентности , определенное operator(), !operator()(a, b) && !operator()(b, a)два shared_­ptr или weak_­ptr экземпляры эквивалентны тогда и только тогда , когда они имеют право собственности или являются пустыми.

end note]

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

Класс T может наследовать от, enable_­shared_­from_­this<T> чтобы наследовать shared_­from_­this функции-члены, которые получают shared_­ptr экземпляр, указывающий на *this.

[Example:

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
  };
}

Параметр шаблона T из enable_­shared_­from_­this может быть неполным типом.

constexpr enable_shared_from_this() noexcept; enable_shared_from_this(const enable_shared_from_this<T>&) noexcept;

Effects: Значение инициализирует weak_­this.

enable_shared_from_this<T>& operator=(const enable_shared_from_this<T>&) noexcept;

Returns: *this.

[ Note: weak_­this не изменено. ] 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.

23.11.2.6 shared_­ptr atomic access [util.smartptr.shared.atomic]

Одновременный доступ к shared_­ptr объекту из нескольких потоков не приводит к гонке за данные, если доступ осуществляется исключительно через функции в этом разделе и экземпляр передается в качестве их первого аргумента.

Значение аргументов типа memory_­order объясняется в [atomics.order].

template<class T> bool atomic_is_lock_free(const shared_ptr<T>* p);

Requires: p не может быть нулевым.

Returns: true если атомарный доступ к *p свободен от блокировки, в false противном случае.

Throws: Ничего такого.

template<class T> shared_ptr<T> atomic_load(const shared_ptr<T>* p);

Requires: p не может быть нулевым.

Returns: atomic_­load_­explicit(p, memory_­order_­seq_­cst).

Throws: Ничего такого.

template<class T> shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo);

Requires: p не может быть нулевым.

Requires: mo не должно быть memory_­order_­release или memory_­order_­acq_­rel.

Returns: *p.

Throws: Ничего такого.

template<class T> void atomic_store(shared_ptr<T>* p, shared_ptr<T> r);

Requires: p не может быть нулевым.

Effects: Как будто мимо atomic_­store_­explicit(p, r, memory_­order_­seq_­cst).

Throws: Ничего такого.

template<class T> void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);

Requires: p не может быть нулевым.

Requires: mo не должно быть memory_­order_­acquire или memory_­order_­acq_­rel.

Effects: Как будто мимо p->swap(r).

Throws: Ничего такого.

template<class T> shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r);

Requires: p не может быть нулевым.

Returns: atomic_­exchange_­explicit(p, r, memory_­order_­seq_­cst).

Throws: Ничего такого.

template<class T> shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);

Requires: p не может быть нулевым.

Effects: Как будто мимо p->swap(r).

Returns: Предыдущее значение *p.

Throws: Ничего такого.

template<class T> bool atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);

Requires: p не может быть нулевым и v не может быть нулевым.

Returns:

atomic_compare_exchange_weak_explicit(p, v, w, memory_order_seq_cst, memory_order_seq_cst)

Throws: Ничего такого.

template<class T> bool atomic_compare_exchange_strong(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);

Returns:

atomic_compare_exchange_strong_explicit(p, v, w, memory_order_seq_cst, memory_order_seq_cst)

template<class T> bool atomic_compare_exchange_weak_explicit( shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w, memory_order success, memory_order failure); template<class T> bool atomic_compare_exchange_strong_explicit( shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w, memory_order success, memory_order failure);

Requires: p не может быть нулевым и v не может быть нулевым. failure Аргумент не должен быть memory_­order_­release ни memory_­order_­acq_­rel.

Effects: Если *p эквивалентно *v, правопреемниками w до *p и имеет семантику синхронизации , соответствующие значению success, в противном случае присваивает *p к *v и имеет семантику синхронизации , соответствующий значению failure.

Returns: true если *p было эквивалентно *v, в false противном случае.

Throws: Ничего такого.

Remarks: Два shared_­ptr объекта эквивалентны, если они хранят одно и то же значение указателя и разделяют владение. Слабая форма может ложно потерпеть неудачу. Смотрите [atomics.types.operations].

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

template <class T, class D> struct hash<unique_ptr<T, D>>;

Позволить UP БЭ unique_­ptr<T,D>, специализация hash<UP> включена ([unord.hash]) , если и только если hash<typename UP​::​pointer> включена. Если эта функция включена, для объекта p типа UP, hash<UP>()(p) должен оценить и то же значение , как hash<typename UP​::​pointer>()(p.get()). Функции-члены не гарантируются noexcept.

template <class T> struct hash<shared_ptr<T>>;

Для объекта p типа shared_­ptr<T>, hash<shared_­ptr<T>>()(p) должен оценить и то же значение , как hash<typename shared_­ptr<T>​::​element_­type*>()(p.get()).