std::unique_ptr
在头文件 <memory> 中定义 |
||
template< class T, |
(1) | (自 C++11 起) |
template < class T, |
(2) | (自 C++11 起) |
std::unique_ptr
是一个智能指针,它拥有(负责)并通过指针管理另一个对象,并在 unique_ptr
超出范围时随后处置该对象。
当以下任一情况发生时,将使用关联的删除器处置该对象
该对象通过调用 get_deleter()(ptr) 使用一个可能是用户提供的删除器来处置。默认删除器 (std::default_delete
) 使用 delete 运算符,该运算符销毁对象并释放内存。
unique_ptr
也可以选择不拥有任何对象,在这种情况下,它被称为空。
std::unique_ptr
有两个版本
- 管理单个对象(例如,使用 new 分配)。
- 管理动态分配的对象数组(例如,使用 new[] 分配)。
该类满足 MoveConstructible 和 MoveAssignable 的要求,但不满足 CopyConstructible 或 CopyAssignable 的要求。
类型要求 | ||
-Deleter 必须是 FunctionObject 或对 FunctionObject 的左值引用,或对函数的左值引用,可调用,参数类型为 unique_ptr<T, Deleter>::pointer。 |
内容 |
[编辑] 备注
只有非 const unique_ptr
可以将托管对象的拥有权转移到另一个 unique_ptr
。如果对象的生存期由 const std::unique_ptr 管理,它将被限制在创建该指针的范围。
std::unique_ptr
通常用于管理对象的生存期,包括
- 为处理具有动态生存期的对象的类和函数提供异常安全性,通过保证在正常退出和通过异常退出时都会进行删除。
- 将具有动态生存期的唯一拥有的对象的拥有权传递给函数。
- 从函数获取具有动态生存期的唯一拥有的对象的拥有权。
- 作为移动感知容器(如 std::vector)中的元素类型,这些容器保存指向动态分配对象的指针(例如,如果需要多态行为)。
std::unique_ptr
可以为 不完整类型 T
构造,例如,为了便于在 pImpl idiom 中用作句柄。如果使用默认删除器,T
必须在代码中调用删除器的点上完整,这发生在 std::unique_ptr
的析构函数、移动赋值运算符和 reset
成员函数中。(相比之下,std::shared_ptr 不能从指向不完整类型的原始指针构造,但可以在 T
不完整的地方销毁)。请注意,如果 T
是类模板特化,则将 unique_ptr
用作操作数,例如 !p 需要 T
的参数完整,因为 ADL。
如果 T
是某个基类 B
的 派生类,那么 std::unique_ptr<T> 可以 隐式转换为 std::unique_ptr<B>。得到的 std::unique_ptr<B> 的默认删除器将使用 operator delete 来删除 B
,这将导致 未定义的行为,除非 B
的析构函数是 虚函数。请注意,std::shared_ptr 的行为不同:std::shared_ptr<B> 将使用 operator delete 来删除类型 T
,即使 B
的析构函数不是 虚函数,托管对象也会被正确删除。
与 std::shared_ptr 不同,std::unique_ptr
可以通过任何满足 NullablePointer 的自定义句柄类型来管理对象。例如,这允许通过提供一个 Deleter
来管理位于共享内存中的对象,该 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 ,要从析构函数调用的函数对象或对函数或函数对象的左值引用 |
[编辑] 成员函数
构造新的 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++11) |
具有共享对象拥有权语义的智能指针 (类模板) |
(C++11) |
对由 std::shared_ptr 管理的对象的弱引用 (类模板) |