std::unique_ptr::unique_ptr
| элементы основного шаблона, unique_ptr<T> |
||
constexpr unique_ptr() noexcept; constexpr unique_ptr( std::nullptr_t ) noexcept; |
(1) | |
explicit unique_ptr( pointer p ) noexcept; |
(2) | (constexpr начиная с C++23) |
unique_ptr( pointer p, /* смотрите ниже */ d1 ) noexcept; |
(3) | (constexpr начиная с C++23) |
unique_ptr( pointer p, /* смотрите ниже */ d2 ) noexcept; |
(4) | (constexpr начиная с C++23) |
unique_ptr( unique_ptr&& u ) noexcept; |
(5) | (constexpr начиная с C++23) |
template< class U, class E > unique_ptr( unique_ptr<U, E>&& u ) noexcept; |
(6) | (constexpr начиная с C++23) |
unique_ptr( const unique_ptr& ) = delete; |
(7) | |
template< class U > unique_ptr( std::auto_ptr<U>&& u ) noexcept; |
(8) | (удалено в C++17) |
| элементы специализации для массивов, unique_ptr<T[]> |
||
constexpr unique_ptr() noexcept; constexpr unique_ptr( std::nullptr_t ) noexcept; |
(1) | |
template< class U > explicit unique_ptr( U p ) noexcept; |
(2) | (constexpr начиная с C++23) |
template< class U > unique_ptr( U p, /* смотрите ниже */ d1 ) noexcept; |
(3) | (constexpr начиная с C++23) |
template< class U > unique_ptr( U p, /* смотрите ниже */ d2 ) noexcept; |
(4) | (constexpr начиная с C++23) |
unique_ptr( unique_ptr&& u ) noexcept; |
(5) | (constexpr начиная с C++23) |
template< class U, class E > unique_ptr( unique_ptr<U, E>&& u ) noexcept; |
(6) | (constexpr начиная с C++23) |
std::unique_ptr, которому ничего не принадлежит. Инициализация со значениями сохраняет указатель и сохраняет средство удаления. Требуется, чтобы Deleter был DefaultConstructible и эта конструкция не вызывала исключения. Эти перегрузки участвуют в разрешении перегрузки, только если std::is_default_constructible<Deleter>::value равно true и Deleter не является указателем.std::unique_ptr, которому принадлежит p, инициализируя сохранённый указатель с помощью p и инициализируя хранимое средство удаления значением. Требуется, чтобы Deleter был DefaultConstructible и эта конструкция не вызывала исключения. Эта перегрузка участвует в разрешении перегрузки, только если std::is_default_constructible<Deleter>::value равно true и Deleter не является указателем.
|
Этот конструктор не выбирается выводом аргумента шаблонного класса. |
(начиная с C++17) |
std::unique_ptr, которому принадлежит p, инициализируя сохранённый указатель с помощью p и инициализируя средство удаления D, как показано ниже (зависит от от того, является ли D ссылочным типом)D не является ссылочным типом A, тогда сигнатура будет:
<tbody>
</tbody> unique_ptr(pointer p, const A& d) noexcept; |
(1) | (требует, чтобы Deleter был негенерирующим исключения CopyConstructible) |
unique_ptr(pointer p, A&& d) noexcept; |
(2) | (требует, чтобы Deleter был негенерирующим исключения MoveConstructible) |
D является типом левосторонней ссылки A&, тогда сигнатура будет:
<tbody>
</tbody> unique_ptr(pointer p, A& d) noexcept; |
(1) | |
unique_ptr(pointer p, A&& d) = delete; |
(2) | |
D является типом левосторонней ссылки const A&, тогда сигнатура будет:
<tbody>
</tbody> unique_ptr(pointer p, const A& d) noexcept; |
(1) | |
unique_ptr(pointer p, const A&& d) = delete; |
(2) | |
std::forward<decltype(d)>(d). Эти перегрузки участвуют в разрешении перегрузки, только если std::is_constructible<D, decltype(d)>::value равно true.
|
Эти два конструктора не выбираются выводом аргумента шаблоного класса. |
(начиная с C++17) |
Uимеет тот же тип, что иpointer, илиUравен std::nullptr_t, илиpointerимеет тот же тип, что иelement_type*, аUнекоторый тип указателяV*, такой чтоV(*)[]неявно преобразуется вelement_type(*)[].
unique_ptr путём передачи владения от u к *this и сохраняет нулевой указатель в u. Этот конструктор участвует в разрешении перегрузки, только если std::is_move_constructible<Deleter>::value равен true. Если Deleter не является ссылочным типом, требуется, чтобы он был негенерирующим исключения MoveConstructible (если Deleter является ссылкой, get_deleter() и u.get_deleter() после создания перемещением ссылаются на одно и то же значение)unique_ptr путём передачи права собственности от u к *this, где u создаётся с указанным средством удаления (E). Это зависит от того, является ли E ссылочным типом, как показано ниже:
E является ссылочным типом, это средство удаления является копией, созданной из средства удаления u (требуется, чтобы эта конструкция не вызывала исключение)E не является ссылочным типом, это средство удаления создаётся из средства удаления u (требуется, чтобы эта конструкция не вызывала исключение)unique_ptr<U, E>::pointer неявно преобразуется в pointerDeleter является ссылочным типом и E имеет тот же тип, что и D, или Deleter не является ссылочным типом и E неявно преобразуется в DUэто тип массиваpointerимеет тот же тип, что иelement_type*unique_ptr<U,E>::pointerимеет тот же тип, что иunique_ptr<U,E>::element_type*unique_ptr<U,E>::element_type(*)[]можно преобразовать вelement_type(*)[]- либо
Deleterявляется ссылочным типом иEимеет тот же тип, что иDeleter, либоDeleterне является ссылочным типом иEнеявно преобразуется вDeleter.
unique_ptr, где сохранённый указатель инициализируется с помощью u.release(), а сохранённое средство удаления инициализируется значением. Этот конструктор участвует в разрешении перегрузки, только если U* неявно преобразуется в T* и Deleter имеет тот же тип, что и std::default_delete<T>.Параметры
| p | — | указатель на объект для управления |
| d1,d2 | — | средство удаления, используемое для уничтожения объекта |
| u | — | другой умный указатель для приобретения права собственности |
Примечание
|
Вместо использования перегрузки (2) вместе с new часто лучше использовать std::make_unique. |
(начиная с C++14) |
std::unique_ptr<Derived> неявно преобразуется в std::unique_ptr<Base> с помощью перегрузки (6) (поскольку и управляемый указатель, и std::default_delete неявно преобразуемы)
Поскольку конструктор по умолчанию является constexpr, статические unique_ptr инициализируются как часть статической нелокальной инициализации до того, как начнётся любая динамическая нелокальная инициализация. Это делает безопасным использование unique_ptr в конструкторе любого статического объекта.
|
Вывод аргумента шаблонного класса из типа указателя невозможен, поскольку невозможно отличить указатель, полученный из форм с массивом и без массива |
(начиная с C++17) |
Пример
#include <iostream>
#include <memory>
struct Foo // объект для управления
{
Foo() { std::cout << "Foo конструктор\n"; }
Foo(const Foo&) { std::cout << "Foo конструктор копирования\n"; }
Foo(Foo&&) { std::cout << "Foo конструктор перемещения\n"; }
~Foo() { std::cout << "~Foo деструктор\n"; }
};
struct D // средство удаления
{
D() {};
D(const D&) { std::cout << "D конструктор копирования\n"; }
D(D&) { std::cout << "D неконстантный конструктор копирования\n";}
D(D&&) { std::cout << "D конструктор перемещения\n"; }
void operator()(Foo* p) const {
std::cout << "D удаляет Foo\n";
delete p;
};
};
int main()
{
std::cout << "Пример конструктора(1)...\n";
std::unique_ptr<Foo> up1; // up1 пуст
std::unique_ptr<Foo> up1b(nullptr); // up1b пуст
std::cout << "Пример конструктора(2)...\n";
{
std::unique_ptr<Foo> up2(new Foo); //up2 теперь владеет Foo
} // Foo удалён
std::cout << "Пример конструктора(3)...\n";
D d;
{ // тип средства удаления не является ссылкой
std::unique_ptr<Foo, D> up3(new Foo, d); // средство удаления скопировано
}
{ // тип средства удаления является ссылкой
std::unique_ptr<Foo, D&> up3b(new Foo, d); // up3b содержит ссылку на d
}
std::cout << "Пример конструктора(4)...\n";
{ // средство удаления не является ссылкой
std::unique_ptr<Foo, D> up4(new Foo, D()); // средство удаления перемещено
}
std::cout << "Пример конструктора(5)...\n";
{
std::unique_ptr<Foo> up5a(new Foo);
std::unique_ptr<Foo> up5b(std::move(up5a)); // передача права собственности
}
std::cout << "Пример конструктора(6)...\n";
{
std::unique_ptr<Foo, D> up6a(new Foo, d); // D копируется
std::unique_ptr<Foo, D> up6b(std::move(up6a)); // D перемещается
std::unique_ptr<Foo, D&> up6c(new Foo, d); // D является ссылкой
std::unique_ptr<Foo, D> up6d(std::move(up6c)); // D копируется
}
#if (__cplusplus < 201703L)
std::cout << "Пример конструктора(7)...\n";
{
std::auto_ptr<Foo> up7a(new Foo);
std::unique_ptr<Foo> up7b(std::move(up7a)); // передача права собственности
}
#endif
std::cout << "Пример конструктора массива...\n";
{
std::unique_ptr<Foo[]> up(new Foo[3]);
} // три объекта Foo удалены
}
Вывод:
Пример конструктора(1)...
Пример конструктора(2)...
Foo конструктор
~Foo деструктор
Пример конструктора(3)...
Foo конструктор
D конструктор копирования
D удаляет Foo
~Foo деструктор
Foo конструктор
D удаляет Foo
~Foo деструктор
Пример конструктора(4)...
Foo конструктор
D конструктор перемещения
D удаляет Foo
~Foo деструктор
Пример конструктора(5)...
Foo конструктор
~Foo деструктор
Пример конструктора(6)...
Foo конструктор
D конструктор копирования
D конструктор перемещения
Foo конструктор
D неконстантный конструктор копирования
D удаляет Foo
~Foo деструктор
D удаляет Foo
~Foo деструктор
Пример конструктора(7)...
Foo конструктор
~Foo деструктор
Пример конструктора массива...
Foo конструктор
Foo конструктор
Foo конструктор
~Foo деструктор
~Foo деструктор
~Foo деструктор
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| LWG 2118 | C++11 | Конструкторы unique_ptr<T[]> отклоняли квалификационные преобразования.
|
Принимают. |
| LWG 2520 | C++11 | unique_ptr<T[]> был случайно сделан неконструируемым из nullptr_t.
|
Сделан конструируемым. |
| LWG 2801 | C++11 | Конструктор по умолчанию не был ограничен. | Ограничен. |
| LWG 2899 | C++11 | Конструктор перемещения не был ограничен. | Ограничен. |
| LWG 2905 | C++11 | Ограничение конструктора указателем и средством удаления было неверным. | Исправлено. |
| LWG 2944 | C++11 | Некоторые предварительные условия были случайно удалены LWG 2905 | Восстановлены. |