Пространства имён
Варианты
Действия

std::shared_ptr::shared_ptr

Материал из cppreference.com
 
 
Библиотека утилит
Языковая поддержка
Поддержка типов (базовые типы, RTTI)
Макросы тестирования функциональности библиотеки (C++20)    
Управление динамической памятью
Программные утилиты
Поддержка сопрограмм (C++20)
Вариативные функции
Трёхстороннее сравнение (C++20)
(C++20)
(C++20)(C++20)(C++20)(C++20)(C++20)(C++20)
Общие утилиты
Дата и время
Функциональные объекты
Библиотека форматирования (C++20)
(C++11)
Операторы отношения (устарело в C++20)
Целочисленные функции сравнения
(C++20)(C++20)(C++20)    
(C++20)
Операции обмена и типа
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
Общие лексические типы
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
Элементарные преобразования строк
(C++17)
(C++17)
 
Динамическое управление памятью
no section name
Ограниченные алгоритмы неинициализированной памяти
no section name
Поддержка сбора мусора
(C++11)(до C++23)
(C++11)(до C++23)
(C++11)(до C++23)
(C++11)(до C++23)
(C++11)(до C++23)
(C++11)(до C++23)



no section name
 
 
<tbody> </tbody>
constexpr shared_ptr() noexcept;
(1)
constexpr shared_ptr( std::nullptr_t ) noexcept;
(2)
template< class Y > explicit shared_ptr( Y* ptr );
(3)
template< class Y, class Deleter > shared_ptr( Y* ptr, Deleter d );
(4)
template< class Deleter > shared_ptr( std::nullptr_t ptr, Deleter d );
(5)
template< class Y, class Deleter, class Alloc > shared_ptr( Y* ptr, Deleter d, Alloc alloc );
(6)
template< class Deleter, class Alloc > shared_ptr( std::nullptr_t ptr, Deleter d, Alloc alloc );
(7)
template< class Y > shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept;
(8)
template< class Y > shared_ptr( shared_ptr<Y>&& r, element_type* ptr ) noexcept;
(8) (начиная с C++20)
shared_ptr( const shared_ptr& r ) noexcept;
(9)
template< class Y > shared_ptr( const shared_ptr<Y>& r ) noexcept;
(9)
shared_ptr( shared_ptr&& r ) noexcept;
(10)
template< class Y > shared_ptr( shared_ptr<Y>&& r ) noexcept;
(10)
template< class Y > explicit shared_ptr( const std::weak_ptr<Y>& r );
(11)
template< class Y > shared_ptr( std::auto_ptr<Y>&& r );
(12) (удалено в C++17)
template< class Y, class Deleter > shared_ptr( std::unique_ptr<Y, Deleter>&& r );
(13)

Создаёт новый shared_ptr из различных типов указателей, которые ссылаются на управляемый объект.

Для целей описания ниже тип указателя Y* считается совместимым с указателем типа T*, если либо Y* преобразуется в T*, либо Y это тип массива U[N] и T это U cv [] (где cv некоторый набор cv-квалификаторов).

(начиная с C++17)
1,2) Создаёт shared_ptr, не управляющий ничем, то есть пустой shared_ptr
3-7) Передаёт простой указатель ptr в автоматическое управление.

Для (3,4,6), Y* должен преобразовываться в T*.

(до C++17)

Если T является массивом типа U[N], (3,4,6) не участвуют в разрешении перегрузки, если Y(*)[N] нельзя преобразовать в T*. Если T является массивом типа U[], (3,4,6) не участвуют в разрешении перегрузки, если Y(*)[] нельзя преобразовать в T*. Иначе (3,4,6) не участвуют в разрешении перегрузки, если Y* не преобразуется в T*.

(начиная с C++17)
Кроме того:
3) Использует выражение delete delete ptr если T не является типом массива; delete[] ptr, если T является типом массива (начиная с C++17) в качестве средства удаления. Y должен быть полным типом. Выражение удаления должно быть корректно, иметь чётко определённое поведение и не вызывать никаких исключений. Этот конструктор также не участвует в разрешении перегрузки, если выражение delete некорректно. (начиная с C++17)
4,5) Использует указанное средство удаления d в качестве средства удаления. Выражение d(ptr) должно быть корректно, иметь чётко определённое поведение и не вызывать никаких исключений. Создание d и скопированного из него хранимого средства удаления не должны вызывать исключений.

Deleter должен быть CopyConstructible.

(до C++17)

Эти конструкторы дополнительно не участвуют в разрешении перегрузки, если выражение d(ptr) некорректно или если std::is_move_constructible<D>::value равно false.

(начиная с C++17)
6,7) То же, что и (4,5), но дополнительно использует копию alloc для выделения данных для внутреннего использования. Alloc должен быть Allocator.
8) Конструктор псевдонимов: создаёт shared_ptr, который разделяет информацию о владении с начальным значением r, но содержит несвязанный и неуправляемый указатель ptr. Если этот shared_ptr последним из группы вышел за пределы области видимости, он вызовет хранимое средство удаления для объекта, изначально управляемого r. Однако вызов get() для этого shared_ptr всегда будет возвращать копию ptr. Программист несёт ответственность за то, чтобы этот ptr оставался действительным до тех пор, пока существует этот shared_ptr, например, в типичных случаях использования, когда ptr является элементом объекта, управляемого r или является псевдонимом (например, downcast) r.get() Для второй перегрузки, принимающей правостороннее значение, r пусто и r.get() == nullptr после вызова. (начиная с C++20)
9) Создаёт shared_ptr , который разделяет владение объектом, управляемым r. Если r не управляет никаким объектом, *this также не управляет никаким объектом. Перегрузка шаблона не участвует в разрешении перегрузки, если Y* не является неявно преобразуемым в (до C++17)совместимым с (начиная с C++17) T*.
10) Создаёт перемещением shared_ptr из r. После создания *this содержит копию предыдущего состояния r, r пуст, а его сохранённый указатель равен нулю. Перегрузка шаблона не участвует в разрешении перегрузки, если Y* не является неявно преобразуемым в (до C++17)совместимым с (начиная с C++17) T*.
11) Создаёт shared_ptr, который разделяет владение объектом, управляемым r. Y* должен быть неявно преобразуем в T*. (до C++17)Эта перегрузка участвует в разрешении перегрузки, только если Y* совместим с T*. (начиная с C++17) Обратите внимание, что r.lock() может использоваться для той же цели: разница в том, что этот конструктор генерирует исключение, если аргумент пуст, а std::weak_ptr<T>::lock() в этом случае создаёт пустой std::shared_ptr.
12) Создаёт shared_ptr, который хранит и владеет объектом, ранее принадлежавшим r. Y* должен быть преобразуем в T*. После построения r пуст.
13) Передаёт объект r из управления unique_ptr под управление нового shared_ptr. Функция удаления, связанная с r, сохраняется для будущего удаления управляемого объекта. После вызова r не управляет никаким объектом.
Эта перегрузка не участвует в разрешении перегрузки, если std::unique_ptr<Y, Deleter>::pointer несовместим с T*. Если r.get() является нулевым указателем, эта перегрузка эквивалентна конструктору по умолчанию (1). (начиная с C++17)
Если Deleter — ссылочный тип, он эквивалентен shared_ptr(r.release(), std::ref(r.get_deleter()). Иначе он эквивалентен shared_ptr(r.release(), std::move(r.get_deleter()))

Когда T не является типом массива, перегрузки (3,4,6) делают доступной shared_from_this с ptr, а перегрузка (13) делает доступной shared_from_this с указателем, возвращаемым r.release().

Параметры

ptr указатель на объект для управления
d средство удаления, используемое для уничтожения объекта
alloc аллокатор, используемый для распределения данных для внутреннего использования
r другой умный указатель для разделения права собственности или получения права владения

Исключения

3) std::bad_alloc, если требуемая дополнительная память не может быть получена. Может генерировать определяемое реализацией исключение для других ошибок. Если возникает исключение, вызывается delete ptr, если T не является типом массива, иначе вызывается delete[] ptr (начиная с C++17).
4-7) std::bad_alloc, если требуемая дополнительная память не может быть получена. Может генерировать определяемое реализацией исключение для других ошибок. d(ptr) вызывается, если возникает исключение.
11) std::bad_weak_ptr, если r.expired() == true. Конструктор в этом случае не действует.
12) std::bad_alloc, если требуемая дополнительная память не может быть получена. Может генерировать определяемое реализацией исключение для других ошибок. Этот конструктор не действует, если возникает исключение.
13) Если возникает исключение, конструктор не действует.

Примечание

Конструктор включает shared_from_this с указателем ptr типа U* и это означает, что он определяет, имеет ли U недвусмысленный и доступный (начиная с C++17) базовый класс, который является специализацией std::enable_shared_from_this, и если это так, конструктор оценивает оператор:

if (ptr != nullptr && ptr->weak_this.expired())
    ptr->weak_this = std::shared_ptr<std::remove_cv_t<U>>(
                         *this, const_cast<std::remove_cv_t<U>*>(ptr));

Где weak_this скрытый mutable элемент std::weak_ptr класса std::enable_shared_from_this. Присваивание элементу weak_this не является атомарным и конфликтует с любым потенциально параллельным доступом к тому же объекту. Это гарантирует, что будущие вызовы shared_from_this() будут совместно владеть std::shared_ptr, созданным этим конструктором сырых указателей.

Тест ptr->weak_this.expired() в приведённом выше описывающем коде гарантирует, что weak_this не будет переприсвоен, если он уже указывает владельца. Этот тест требуется начиная с C++17.

Перегрузки сырого указателя предполагают владение объектом, на который он указывает. Таким образом, создание shared_ptr с использованием перегрузки сырого указателя для объекта, которым уже управляет shared_ptr, например shared_ptr(ptr.get()), может привести к неопределённому поведению, даже если объект имеет тип, производный от std::enable_shared_from_this.

Поскольку конструктор по умолчанию является constexpr, статические shared_ptr инициализируются как часть статической нелокальной инициализации до того, как начнётся любая динамическая нелокальная инициализация. Это делает безопасным использование shared_ptr в конструкторе любого статического объекта.

В C++11 и C++14 можно создать std::shared_ptr<T> из std::unique_ptr<T[]>:

std::unique_ptr<int[]> arr(new int[1]);
std::shared_ptr<int> ptr(std::move(arr));

Поскольку shared_ptr получает средство удаления (объект std::default_delete<T[]>) из std::unique_ptr, массив будет правильно освобождён.

Это больше не разрешено в C++17. Вместо этого следует использовать форму массива std::shared_ptr<T[]>.

Пример

#include <memory>
#include <iostream>

struct Foo {
    int id{0};
    Foo(int i = 0) : id{i} { std::cout << "Foo::Foo(" << i <<  ")\n"; }
    ~Foo() { std::cout << "Foo::~Foo(), id=" << id << '\n'; }
};

struct D {
    void operator()(Foo* p) const {
        std::cout << "Вызов delete из функционального объекта. Foo::id=" << p->id << '\n';
        delete p;
    }
};

int main()
{
    {
        std::cout << "1) конструктор без управляемого объекта\n";
        std::shared_ptr<Foo> sh1;
    }

    {
        std::cout << "2) конструктор с объектом\n";
        std::shared_ptr<Foo> sh2(new Foo{10});
        std::cout << "sh2.use_count(): " << sh2.use_count() << '\n';
        std::shared_ptr<Foo> sh3(sh2);
        std::cout << "sh2.use_count(): " << sh2.use_count() << '\n';
        std::cout << "sh3.use_count(): " << sh3.use_count() << '\n';
    }

    {
        std::cout << "3) конструктор с объектом и средством удаления\n";
        std::shared_ptr<Foo> sh4(new Foo{11}, D());
        std::shared_ptr<Foo> sh5(new Foo{12}, [](auto p) {
           std::cout << "Вызов delete из лямбды... p->id=" << p->id << '\n';
           delete p;
        });
    }
}

Вывод:

1) конструктор без управляемого объекта
2) конструктор с объектом
Foo::Foo(10)
sh2.use_count(): 1
sh2.use_count(): 2
sh3.use_count(): 2
Foo::~Foo(), id=10
3) конструктор с объектом и средством удаления
Foo::Foo(11)
Foo::Foo(12)
Вызов delete из лямбды... p->id=12
Foo::~Foo(), id=12
Вызов delete из функционального объекта. Foo::id=11
Foo::~Foo(), id=11

Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
LWG 3548 C++11 конструктор из unique_ptr создавал копированием средство удаления вместо этого создаёт перемещением

Смотрите также

создаёт общий указатель, который управляет новым объектом
(шаблон функции) [править]
создаёт общий указатель, который управляет новым объектом, выделенным с помощью аллокатора
(шаблон функции) [править]
позволяет объекту создавать shared_ptr, ссылаясь на себя
(шаблон класса) [править]