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:
- Управляет одним объектом (например, выделенным с помощью
new). - Управляет динамически выделенным массивом объектов (например, выделенным с помощью
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 (публичный член-функция) |
|
| уничтожает управляемый объект, если он присутствует (публичный член-функция) |
|
присваивает unique_ptr (публичный член-функция) |
|
Модификаторы |
|
| возвращает указатель на управляемый объект и освобождает владение (публичный член-функция) |
|
| заменяет управляемый объект (публичный член-функция) |
|
| меняет местами управляемые объекты (публичный член-функция) |
|
Наблюдатели |
|
| возвращает указатель на управляемый объект (публичный член-функция) |
|
| возвращает удалитель, используемый для уничтожения управляемого объекта (публичный член-функция) |
|
| проверяет наличие связанного управляемого объекта (публичный член-функция) |
|
Версия для одного объекта, |
|
| обращается к указателю на управляемый объект (публичный член-функция) |
|
Версия для массива, |
|
| обеспечивает индексированный доступ к управляемому массиву (публичный член-функция) |
|
Внешние функции
|
(C++14)(C++20) | создаёт указатель unique, управляющий новым объектом (шаблон функции) |
|
(удалено в C++20)(C++20) | сравнивает с другим unique_ptr или с nullptr (шаблон функции) |
|
(C++20) | выводит значение управляемого указателя в поток вывода (шаблон функции) |
|
(C++11) | специализирует алгоритм std::swap (шаблон функции) |
Вспомогательные классы
|
(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...
См. также
|
(C++11) | умный указатель с семантикой совместного владения объектом (шаблон класса) |
|
(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