Spec-Zone.ru › C++

std::unique_ptr

Определено в заголовочном файле <memory>
template<
    class T,
    class Deleter = std::default_delete<T>
> class unique_ptr;
(1) (с C++11)
template <
    class T,
    class Deleter
> class unique_ptr<T[], Deleter>;
(2) (с C++11)

std::unique_ptr — это умный указатель, который владеет и управляет другим объектом через указатель и удаляет этот объект, когда unique_ptr выходит за пределы области видимости.

Объект удаляется с использованием связанного удалителя, когда происходит одно из следующих событий:

  • управляющий unique_ptr объект уничтожается.
  • управляющий unique_ptr объект присваивается другой указатель через operator= или reset().

Объект удаляется, используя потенциально предоставленный пользователем удалитель, вызывая get_deleter()(ptr). По умолчанию удалитель использует оператор delete, который уничтожает объект и освобождает память.

unique_ptr может альтернативно не владеть никаким объектом, в этом случае он называется пустым.

Существует две версии std::unique_ptr:

  1. Управляет одним объектом (например, выделенным с помощью new).
  2. Управляет динамически выделенным массивом объектов (например, выделенным с помощью new[]).

Класс удовлетворяет требованиям MoveConstructible и MoveAssignable, но ни CopyConstructible ни CopyAssignable.

Требования к типу
-Deleter должен быть FunctionObject или ссылкой на lvalue на FunctionObject или ссылкой на lvalue на функцию, вызываемую с аргументом типа unique_ptr<T, Deleter>::pointer.

Примечания

Только неконстантный unique_ptr может передать владение управляемым объектом другому unique_ptr. Если жизненный цикл объекта управляется const std::unique_ptr, он ограничен областью видимости, в которой указатель был создан.

std::unique_ptr часто используется для управления жизненным циклом объектов, включая:

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

std::unique_ptr может быть создан для неполного типа T, например, для использования в качестве дескриптора в идиоме pImpl. Если используется удалитель по умолчанию, T должен быть полным в той точке кода, где вызывается удалитель, что происходит в деструкторе, операторе присваивания перемещением и функции-члене reset std::unique_ptr. (Обратно, std::shared_ptr не может быть создан из сырого указателя на неполный тип, но может быть уничтожен, когда T неполный). Обратите внимание, что если T — это специализация шаблона класса, использование unique_ptr в качестве операнда, например, !p требует, чтобы параметры T были полными из-за ADL.

Если T — это производный класс от некоторого базового B, то std::unique_ptr<T> неявно преобразуется в std::unique_ptr<B>. Удалитель по умолчанию для результирующего std::unique_ptr<B> будет использовать оператор delete для B, что приведёт к неопределённому поведению, если деструктор B не является виртуальным. Обратите внимание, что std::shared_ptr ведет себя по-другому: std::shared_ptr<B> будет использовать оператор delete для типа T и управляемый объект будет удалён корректно, даже если деструктор B не является виртуальным.

В отличие от std::shared_ptr, std::unique_ptr может управлять объектом с помощью любого пользовательского типа дескриптора, который удовлетворяет NullablePointer. Это позволяет, например, управлять объектами, расположенными в общей памяти, предоставив Deleter , который определяет typedef boost::offset_ptr pointer; или другой специализированный указатель.

Макросы для проверки наличия функций Значение Std Функция
__cpp_lib_constexpr_memory 202202L (C++23) constexpr std::unique_ptr

Типы членов

Тип члена Определение
pointer std::remove_reference<Deleter>::type::pointer если такой тип существует, в противном случае T*. Должен удовлетворять NullablePointer
element_type T, тип объекта, управляемого этим unique_ptr
deleter_type Deleter, объект-функция или ссылка на lvalue на функцию или объект-функцию, вызываемую из деструктора

Члены-функции

(конструктор)
создаёт новый unique_ptr
(публичный член-функция)
(деструктор)
уничтожает управляемый объект, если он присутствует
(публичный член-функция)
operator=
присваивает unique_ptr
(публичный член-функция)
Модификаторы
release
возвращает указатель на управляемый объект и освобождает владение
(публичный член-функция)
reset
заменяет управляемый объект
(публичный член-функция)
swap
меняет местами управляемые объекты
(публичный член-функция)
Наблюдатели
get
возвращает указатель на управляемый объект
(публичный член-функция)
get_deleter
возвращает удалитель, используемый для уничтожения управляемого объекта
(публичный член-функция)
operator bool
проверяет наличие связанного управляемого объекта
(публичный член-функция)
Версия для одного объекта, unique_ptr<T>
operator*operator->
обращается к указателю на управляемый объект
(публичный член-функция)
Версия для массива, unique_ptr<T[]>
operator[]
обеспечивает индексированный доступ к управляемому массиву
(публичный член-функция)

Внешние функции

make_uniquemake_unique_for_overwrite
(C++14)(C++20)
создаёт указатель unique, управляющий новым объектом
(шаблон функции)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(удалено в C++20)(C++20)
сравнивает с другим unique_ptr или с nullptr
(шаблон функции)
operator<<(std::unique_ptr)
(C++20)
выводит значение управляемого указателя в поток вывода
(шаблон функции)
std::swap(std::unique_ptr)
(C++11)
специализирует алгоритм std::swap
(шаблон функции)

Вспомогательные классы

std::hash<std::unique_ptr>
(C++11)
поддержка хеширования для std::unique_ptr
(специализация шаблона класса)

Пример

#include <cassert>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <locale>
#include <memory>
#include <stdexcept>
 
// helper class for runtime polymorphism demo below
struct B
{
    virtual ~B() = default;
 
    virtual void bar() { std::cout << "B::bar\n"; }
};
 
struct D : B
{
    D() { std::cout << "D::D\n"; }
    ~D() { std::cout << "D::~D\n"; }
 
    void bar() override { std::cout << "D::bar\n"; }
};
 
// a function consuming a unique_ptr can take it by value or by rvalue reference
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
    p->bar();
    return p;
}
 
// helper function for the custom deleter demo below
void close_file(std::FILE* fp)
{
    std::fclose(fp);
}
 
// unique_ptr-based linked list demo
struct List
{
    struct Node
    {
        int data;
        std::unique_ptr<Node> next;
    };
 
    std::unique_ptr<Node> head;
 
    ~List()
    {
        // destroy list nodes sequentially in a loop, the default destructor
        // would have invoked its `next`'s destructor recursively, which would
        // cause stack overflow for sufficiently large lists.
        while (head)
        {
            auto next = std::move(head->next);
            head = std::move(next);
        }
    }
 
    void push(int data)
    {
        head = std::unique_ptr<Node>(new Node{data, std::move(head)});
    }
};
 
int main()
{
    std::cout << "1) Unique ownership semantics demo\n";
    {
        // Create a (uniquely owned) resource
        std::unique_ptr<D> p = std::make_unique<D>();
 
        // Transfer ownership to `pass_through`,
        // which in turn transfers ownership back through the return value
        std::unique_ptr<D> q = pass_through(std::move(p));
 
        // p is now in a moved-from 'empty' state, equal to nullptr
        assert(!p);
    }
 
    std::cout << "\n" "2) Runtime polymorphism demo\n";
    {
        // Create a derived resource and point to it via base type
        std::unique_ptr<B> p = std::make_unique<D>();
 
        // Dynamic dispatch works as expected
        p->bar();
    }
 
    std::cout << "\n" "3) Custom deleter demo\n";
    std::ofstream("demo.txt") << 'x'; // prepare the file to read
    {
        using unique_file_t = std::unique_ptr<std::FILE, decltype(&close_file)>;
        unique_file_t fp(std::fopen("demo.txt", "r"), &close_file);
        if (fp)
            std::cout << char(std::fgetc(fp.get())) << '\n';
    } // `close_file()` called here (if `fp` is not null)
 
    std::cout << "\n" "4) Custom lambda-expression deleter and exception safety demo\n";
    try
    {
        std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr)
        {
            std::cout << "destroying from a custom deleter...\n";
            delete ptr;
        });
 
        throw std::runtime_error(""); // `p` would leak here if it were a plain pointer
    }
    catch (const std::exception&)
    {
        std::cout << "Caught exception\n";
    }
 
    std::cout << "\n" "5) Array form of unique_ptr demo\n";
    {
        std::unique_ptr<D[]> p(new D[3]);
    } // `D::~D()` is called 3 times
 
    std::cout << "\n" "6) Linked list demo\n";
    {
        List wall;
        const int enough{1'000'000};
        for (int beer = 0; beer != enough; ++beer)
            wall.push(beer);
 
        std::cout.imbue(std::locale("en_US.UTF-8"));
        std::cout << enough << " bottles of beer on the wall...\n";
    } // destroys all the beers
}

Возможный вывод:

1) Unique ownership semantics demo
D::D
D::bar
D::~D
 
2) Runtime polymorphism demo
D::D
D::bar
D::~D
 
3) Custom deleter demo
x
 
4) Custom lambda-expression deleter and exception safety demo
D::D
destroying from a custom deleter...
D::~D
Caught exception
 
5) Array form of unique_ptr demo
D::D
D::D
D::D
D::~D
D::~D
D::~D
 
6) Linked list demo
1,000,000 bottles of beer on the wall...

См. также

shared_ptr
(C++11)
умный указатель с семантикой совместного владения объектом
(шаблон класса)
weak_ptr
(C++11)
слабая ссылка на объект, управляемый std::shared_ptr
(шаблон класса)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/memory/unique_ptr

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API