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

std::unique_ptr::unique_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>
элементы основного шаблона, 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)
1) Создаёт std::unique_ptr, которому ничего не принадлежит. Инициализация со значениями сохраняет указатель и сохраняет средство удаления. Требуется, чтобы Deleter был DefaultConstructible и эта конструкция не вызывала исключения. Эти перегрузки участвуют в разрешении перегрузки, только если std::is_default_constructible<Deleter>::value равно true и Deleter не является указателем.
2) Создаёт std::unique_ptr, которому принадлежит p, инициализируя сохранённый указатель с помощью p и инициализируя хранимое средство удаления значением. Требуется, чтобы Deleter был DefaultConstructible и эта конструкция не вызывала исключения. Эта перегрузка участвует в разрешении перегрузки, только если std::is_default_constructible<Deleter>::value равно true и Deleter не является указателем.

Этот конструктор не выбирается выводом аргумента шаблонного класса.

(начиная с C++17)
3,4) Создаёт объект std::unique_ptr, которому принадлежит p, инициализируя сохранённый указатель с помощью p и инициализируя средство удаления D, как показано ниже (зависит от от того, является ли D ссылочным типом)
a) Если 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)
b) Если D является типом левосторонней ссылки A&, тогда сигнатура будет: <tbody> </tbody>
unique_ptr(pointer p, A& d) noexcept;
(1)
unique_ptr(pointer p, A&& d) = delete;
(2)
c) Если 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)
2-4) В специализации для массивов ведут себя так же, как конструкторы, принимающие параметр-указатель в основном шаблоне, за исключением того, что они дополнительно не участвуют в разрешении перегрузки, если не выполняется одно из следующих условий:
  • U имеет тот же тип, что и pointer, или
  • U равен std::nullptr_t, или
  • pointer имеет тот же тип, что и element_type*, а U некоторый тип указателя V*, такой что V(*)[] неявно преобразуется в element_type(*)[].
5) Создаёт unique_ptr путём передачи владения от u к *this и сохраняет нулевой указатель в u. Этот конструктор участвует в разрешении перегрузки, только если std::is_move_constructible<Deleter>::value равен true. Если Deleter не является ссылочным типом, требуется, чтобы он был негенерирующим исключения MoveConstructible (если Deleter является ссылкой, get_deleter() и u.get_deleter() после создания перемещением ссылаются на одно и то же значение)
6) Создаёт unique_ptr путём передачи права собственности от u к *this, где u создаётся с указанным средством удаления (E). Это зависит от того, является ли E ссылочным типом, как показано ниже:
a) если E является ссылочным типом, это средство удаления является копией, созданной из средства удаления u (требуется, чтобы эта конструкция не вызывала исключение)
b) если E не является ссылочным типом, это средство удаления создаётся из средства удаления u (требуется, чтобы эта конструкция не вызывала исключение)
Этот конструктор участвует в разрешении перегрузки только в том случае, если выполняются все следующие условия:
a) unique_ptr<U, E>::pointer неявно преобразуется в pointer
b) U не является типом массива
c) либо Deleter является ссылочным типом и E имеет тот же тип, что и D, или Deleter не является ссылочным типом и E неявно преобразуется в D
6) В специализации для массивов ведёт себя так же, как и в первичном шаблоне, за исключением того, что он будет участвовать в разрешении перегрузки только в том случае, если верно всё следующее
  • U это тип массива
  • 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.
7) Конструктор копирования явно удалён.
8) Создаёт 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 в конструкторе любого статического объекта.

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

(начиная с 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 Восстановлены.