std::shared_ptr::shared_ptr
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 из различных типов указателей, которые ссылаются на управляемый объект.
|
Для целей описания ниже тип указателя |
(начиная с C++17) |
shared_ptr, не управляющий ничем, то есть пустой shared_ptrptr в автоматическое управление.
|
Для (3,4,6), |
(до C++17) |
|
Если |
(начиная с C++17) |
delete ptr если T не является типом массива; delete[] ptr, если T является типом массива (начиная с C++17) в качестве средства удаления. Y должен быть полным типом. Выражение удаления должно быть корректно, иметь чётко определённое поведение и не вызывать никаких исключений. Этот конструктор также не участвует в разрешении перегрузки, если выражение delete некорректно. (начиная с C++17)d в качестве средства удаления. Выражение d(ptr) должно быть корректно, иметь чётко определённое поведение и не вызывать никаких исключений. Создание d и скопированного из него хранимого средства удаления не должны вызывать исключений.
|
|
(до C++17) |
|
Эти конструкторы дополнительно не участвуют в разрешении перегрузки, если выражение |
(начиная с C++17) |
alloc для выделения данных для внутреннего использования. Alloc должен быть Allocator.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)shared_ptr , который разделяет владение объектом, управляемым r. Если r не управляет никаким объектом, *this также не управляет никаким объектом. Перегрузка шаблона не участвует в разрешении перегрузки, если Y* не является неявно преобразуемым в (до C++17)совместимым с (начиная с C++17) T*.shared_ptr из r. После создания *this содержит копию предыдущего состояния r, r пуст, а его сохранённый указатель равен нулю. Перегрузка шаблона не участвует в разрешении перегрузки, если Y* не является неявно преобразуемым в (до C++17)совместимым с (начиная с C++17) T*.shared_ptr, который разделяет владение объектом, управляемым r. Y* должен быть неявно преобразуем в T*. (до C++17)Эта перегрузка участвует в разрешении перегрузки, только если Y* совместим с T*. (начиная с C++17) Обратите внимание, что r.lock() может использоваться для той же цели: разница в том, что этот конструктор генерирует исключение, если аргумент пуст, а std::weak_ptr<T>::lock() в этом случае создаёт пустой std::shared_ptr.shared_ptr, который хранит и владеет объектом, ранее принадлежавшим r. Y* должен быть преобразуем в T*. После построения r пуст.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 | — | другой умный указатель для разделения права собственности или получения права владения |
Исключения
delete ptr, если T не является типом массива, иначе вызывается delete[] ptr (начиная с C++17).d(ptr) вызывается, если возникает исключение.r.expired() == true. Конструктор в этом случае не действует.Примечание
Конструктор включает 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 создавал копированием средство удаления
|
вместо этого создаёт перемещением |
Смотрите также
| создаёт общий указатель, который управляет новым объектом (шаблон функции) | |
| создаёт общий указатель, который управляет новым объектом, выделенным с помощью аллокатора (шаблон функции) | |
(C++11) |
позволяет объекту создавать shared_ptr, ссылаясь на себя (шаблон класса) |