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
也可以不拥有任何对象,在这种情况下,它被描述为空。
unique_ptr
有两个版本
- 管理单个对象(例如,使用 new 分配)。
- 管理动态分配的对象数组(例如,使用 new[] 分配)。
该类满足 MoveConstructible 和 MoveAssignable 的要求,但不满足 CopyConstructible 和 CopyAssignable 的要求。
如果 T*
不是有效类型(例如,T
是引用类型),则实例化 std::unique_ptr<T, Deleter> 定义的程序是非良构的。
类型要求 | ||
-Deleter 必须是 FunctionObject 或对 FunctionObject 的左值引用,或对函数的左值引用,可使用类型为 unique_ptr<T, Deleter>::pointer 的参数调用。 |
内容 |
[编辑] 注解
只有非 const 的 unique_ptr
可以将托管对象的所有权转移到另一个 unique_ptr
。如果对象的生命周期由 const std::unique_ptr 管理,则它仅限于创建指针的作用域。
unique_ptr
通常用于管理对象的生命周期,包括
- 通过保证在正常退出和通过异常退出时都进行删除,为处理具有动态生命周期的对象的类和函数提供异常安全性。
- 将唯一拥有的具有动态生命周期的对象的所有权传递给函数。
- 从函数获取唯一拥有的具有动态生命周期的对象的所有权。
- 作为可移动感知容器(如 std::vector)中的元素类型,这些容器保存指向动态分配对象的指针(例如,如果需要多态行为)。
可以为不完整类型 T
构造 unique_ptr
,例如,为了方便在 pImpl 惯用法中用作句柄。如果使用默认删除器,则 T
必须在调用删除器的代码点处是完整的,这发生在 unique_ptr
的析构函数、移动赋值运算符和 reset
成员函数中。(相比之下,不能从指向不完整类型的原始指针构造 std::shared_ptr,但可以在 T
不完整时销毁)。请注意,如果 T
是类模板特化,则由于 ADL,将 unique_ptr
用作操作数(例如 !p)需要 T
的参数是完整的。
如果 T
是某个基类 B
的派生类,则 unique_ptr<T> 可以隐式转换为 unique_ptr<B>。生成的 unique_ptr<B> 的默认删除器将对 B
使用 operator delete,除非 B
的析构函数是 虚函数,否则会导致未定义行为。请注意,std::shared_ptr 的行为有所不同:std::shared_ptr<B> 将对类型 T
使用 operator delete,即使 B
的析构函数不是 虚函数,拥有的对象也将被正确删除。
与 std::shared_ptr 不同,unique_ptr
可以通过满足 NullablePointer 的任何自定义句柄类型来管理对象。例如,这允许通过提供定义 typedef boost::offset_ptr pointer;
或另一个 花式指针的 Deleter
来管理位于共享内存中的对象。
特性测试 宏 | 值 | 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) |
创建管理新对象的 unique pointer (函数模板) |
(在 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 管理的对象的弱引用 (类模板) |