std::unique_ptr - cppreference.com
std::unique_ptr
动态内存管理
std::unique_ptr
|
在标头 <memory> 定义 |
|
|
template < class T, class Deleter = std::default_delete<T> > class unique_ptr; |
(C++11 起) |
|
template < class T, class Deleter > class unique_ptr<T[], Deleter> ; |
(C++11 起) |
std::unique_ptr 是通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象的智能指针。
在下列两者之一发生时用关联的删除器释放对象:
- 销毁了管理的 unique_ptr 对象
- 通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr 对象。
通过调用 get_deleter ()(ptr) ,用潜在为用户提供的删除器释放对象。默认删除器用 delete 运算符,它销毁对象并解分配内存。
unique_ptr 亦可以不占有对象,该情况下称它为 空 (empty) 。
std::unique_ptr 有两个版本:
1) 管理单个对象(例如以 new 分配)
2) 管理动态分配的对象数组(例如以 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 手法中柄的用途。若使用默认删除器,则 T 必须在代码中调用删除器点处完整,这发生于析构函数、移动赋值运算符和 std::unique_ptr 的 reset 成员函数中。(相反地, std::shared_ptr 不能从指向不完整类型的裸指针构造,但可于 T 不完整处销毁)。注意若 T 是类模板特化,则以 unique_ptr 为运算数的使用,如 !p ,因 ADL 而要求 T 的形参完整。
若 T 是某基类 B 的派生类,则 std ::unique_ptr<T> 可隐式转换为 std::unique_ptr<B>。产生的 std::unique_ptr<B> 的默认删除器将使用 B 的 operator delete ,这导致未定义行为,除非 B 的析构函数为虚。注意 std::shared_ptr 表现有别: std::shared_ptr<B> 将使用类型 T 的 operator delete ,而且即使 B 的析构函数非虚,也会正确删除被占有对象。
不同于 std::shared_ptr , std::unique_ptr 可通过任何满足 可空指针 (NullablePointer) 的定制柄类型管理对象。例如,这允许管理位于共享内存,但提供定义 typedef boost::offset_ptr pointer; 或其他缀饰指针的 Deleter 的对象。
|
功能特性测试宏 |
值 |
标准 |
功能特性 |
|
__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 (公开成员函数) |
|
(析构函数) |
析构所管理的对象,如果存在的话 (公开成员函数) |
|
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) |
创建管理一个新对象的独占指针 (函数模板) |
|
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20) |
与另一个 unique_ptr 或 nullptr 进行比较 (函数模板) |
|
operator<< (C++20) |
输出被管理指针的值到输出流 (函数模板) |
|
std::swap(std::unique_ptr) (C++11) |
特化 std::swap 算法 (函数模板) |
辅助类
|
std::hash<std::unique_ptr> (C++11) |
std::unique_ptr 的散列支持 (类模板特化) |
示例
运行此代码
#include <iostream>
#include <vector>
#include <memory>
#include <cstdio>
#include <fstream>
#include <cassert>
#include <functional>
struct B {
virtual void bar() { std::cout << "B::bar\n"; }
virtual ~B() = default;
};
struct D : B
{
D() { std::cout << "D::D\n"; }
~D() { std::cout << "D::~D\n"; }
void bar() override { std::cout << "D::bar\n"; }
};
// 消费 unique_ptr 的函数能以值或以右值引用接收它
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
p->bar();
return p;
}
void close_file(std::FILE* fp) { std::fclose(fp); }
int main()
{
std::cout << "unique ownership semantics demo\n";
{
auto p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr
auto q = pass_through(std::move(p));
assert(!p); // 现在 p 不占有任何内容并保有空指针
q->bar(); // 而 q 占有 D 对象
} // ~D 调用于此
std::cout << "Runtime polymorphism demo\n";
{
std::unique_ptr<B> p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr
// 作为指向基类的指针
p->bar(); // 虚派发
std::vector<std::unique_ptr<B>> v; // unique_ptr 能存储于容器
v.push_back(std::make_unique<D>());
v.push_back(std::move(p));
v.emplace_back(new D);
for(auto& p: v) p->bar(); // 虚派发
} // ~D called 3 times
std::cout << "Custom deleter demo\n";
std::ofstream("demo.txt") << 'x'; // 准备要读的文件
{
std::unique_ptr<std::FILE, void (*)(std::FILE*) > fp(std::fopen("demo.txt", "r"),
close_file);
if(fp) // fopen 可以打开失败;该情况下 fp 保有空指针
std::cout << (char)std::fgetc(fp.get()) << '\n';
} // fclose() 调用于此,但仅若 FILE* 不是空指针
// (即 fopen 成功)
std::cout << "Custom lambda-expression deleter demo\n";
{
std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr)
{
std::cout << "destroying from a custom deleter...\n";
delete ptr;
}); // p 占有 D
p->bar();
} // 调用上述 lambda 并销毁 D
std::cout << "Array form of unique_ptr demo\n";
{
std::unique_ptr<D[]> p{new D[3]};
} // 调用 ~D 3 次
}
输出:
unique ownership semantics demo
D::D
D::bar
D::bar
D::~D
Runtime polymorphism demo
D::D
D::bar
D::D
D::D
D::bar
D::bar
D::bar
D::~D
D::~D
D::~D
Custom deleter demo
x
Custom lambda-expression deleter demo
D::D
D::bar
destroying from a custom deleter...
D::~D
Array form of unique_ptr demo
D::D
D::D
D::D
D::~D
D::~D
D::~D