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). Удалитель по умолчанию (std::default_delete) использует оператор delete, который уничтожает объект и освобождает память.
unique_ptr также может не владеть объектом; в этом случае он называется пустым.
Существует две версии unique_ptr:
- Управляет одним объектом (например, выделенным с помощью new).
- Управляет динамически выделенным массивом объектов (например, выделенным с помощью new[]).
Класс удовлетворяет требованиям MoveConstructible и MoveAssignable, но не удовлетворяет требованиям CopyConstructible и CopyAssignable.
Если T* не является допустимым типом (например, T является ссылочным типом), программа, в которой инстанцируется определение std::unique_ptr<T,Deleter>, некорректна.
| Требования к типам | ||
-Deleter должен быть FunctionObject, ссылкой на lvalue типа FunctionObject или ссылкой на lvalue на функцию, вызываемую с аргументом типа unique_ptr<T,Deleter>::pointer. |
Примечания
Только неконстантный unique_ptr может передать владение управляемым объектом другому unique_ptr. Если временем жизни объекта управляет conststd::unique_ptr, оно ограничено областью видимости, в которой был создан указатель.
unique_ptr обычно используется для управления временем жизни объектов, в том числе для:
- обеспечения безопасности при исключениях в классах и функциях, работающих с объектами с динамическим временем жизни, гарантируя удаление как при обычном выходе, так и при выходе из-за исключения.
- передачи владения уникально принадлежащими объектами с динамическим временем жизни функциям.
- получения от функций владения уникально принадлежащими объектами с динамическим временем жизни.
- использования в качестве типа элементов в контейнерах, поддерживающих перемещение, таких как
std::vector, которые содержат указатели на динамически выделенные объекты (например, если требуется полиморфное поведение).
unique_ptr может быть создан для неполного типа T, например, чтобы использовать его в качестве дескриптора в идиоме pImpl. Если используется удалитель по умолчанию, T должен быть полным в точке кода, где вызывается удалитель; это происходит в деструкторе, операторе присваивания перемещением и функции-члене reset класса unique_ptr. (В отличие от этого, std::shared_ptr нельзя создать из сырого указателя на неполный тип, однако его можно уничтожить, когда T является неполным). Обратите внимание: если T является специализацией шаблона класса, использование unique_ptr в качестве операнда, например !p, требует полноты параметров T из-за ADL.
Если T является производным классом некоторого базового класса B, то unique_ptr<T> неявно преобразуется в unique_ptr<B>. Удалитель по умолчанию полученного unique_ptr<B> будет использовать operator delete для B, что приводит к неопределённому поведению, если деструктор B не является виртуальным. Обратите внимание, что std::shared_ptr ведёт себя иначе: std::shared_ptr<B> будет использовать operator delete для типа T, и принадлежащий ему объект будет корректно удалён, даже если деструктор B не является виртуальным.
В отличие от std::shared_ptr, unique_ptr может управлять объектом с помощью любого пользовательского типа дескриптора, удовлетворяющего требованиям NullablePointer. Это позволяет, например, управлять объектами в разделяемой памяти, предоставив Deleter, который определяет typedef boost::offset_ptr pointer; или другой специальный указатель.
| Макрос проверки наличия возможности | Значение | Стандарт | Возможность |
|---|---|---|---|
__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) | создаёт уникальный указатель, управляющий новым объектом (шаблон функции) |
|
(удалены в 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++.
| DR | Применён к | Опубликованное поведение | Корректное поведение |
|---|---|---|---|
| LWG 4144 | C++11 |
T* не требовалось образовывать допустимый тип | требуется |
См. также
|
(C++11) | умный указатель с семантикой совместного владения объектом (шаблон класса) |
|
(C++11) | слабая ссылка на объект, управляемый std::shared_ptr (шаблон класса) |
|
(C++26) | обёртка, содержащая динамически выделенный объект с семантикой, подобной семантике значения (шаблон класса) |
|
(C++17) | объекты, хранящие экземпляры любого типа, удовлетворяющего требованиям CopyConstructible (класс) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/memory/unique_ptr