悠泥客指针
unique_ptr
1. 简介
C++
为编程人员提供了3种智能指针--std::shared_ptr,
std::unique_ptr, std::weak_ptr. 本文先介绍
std::unique_ptr,
该类型的指针能够管理堆上的对象, 同时在适当时候(作用域外)释放内存.
应当说明 unique_ptr 定义在头文件
1
2
3
4
5
6
7
8
9template<
class T,
class Deleter = std::default_delete<T>
> class unique_ptr;
///
template<
class T,
class Deleter
> class unique_ptr<T[], Deleter>;
- unique_ptr 所管理的对象被销毁
- 通过重写的赋值运算 operator= 或者 公有成员函数 reset() 将 unique_ptr 管理的对象赋给其他指针.
调用 get_deleter()(ptr)
使用用户提供的删除器释放
unique_ptr 对象. 默认的删除器要使用
delete
运算符来销毁对象并释放对象占据的内存.
当然, unique_ptr 也可以不指向任何对象, 此时即为空.
unique_ptr 管理对象的方法有两种:
- 使用
new
创建单个对象 - 使用
new[]
管理动态分配的对象数组(释放内存也要使用对应的删除器).
优雅使用 unique_ptr 的注意事项:
可以想见的是, 对象所有权只能在 non-const
unique_ptr 之间进行转移. 如果对象是由
const std::unique_str
来管理的, 那该对象只受作用域的限制.
unique_ptr 通常用来管理对象的生存期,
包括:
- 通过确保在(程序)正常退出和抛出异常退出两种情况下都能正常删除对象, 为处理具有动态生存期的对象的类或者函数提供一种异常安全的机制.
- 将独占的具有动态生存期的对象传递到函数中.
- 从函数获取独占的具有动态生存期的对象.
- 可以作为可移动容器的元素类型, 比如保有指向动态分配对象的指针的容器 std::vector.
std::unique_ptr 可为不完整类型 T 构造,
例如可以用于改善 plmpl
方法中句柄的用途. 若使用默认删除器, 在调用点处, T 必须是完整的类型,
例如在调用析构函数, 使用移动赋值运算符以及调用
std::unique_ptr 的成员函数
reset() 的时候. 相反地, 不能将
std::shared_ptr 从原始指针 (raw pointer)
构造成不完整类型, 但是当 T 是不完整类型时可以被销毁. 应当注意的是, 如果
T 是一个类模板的特化, 则 std::unique_ptr
作为操作数使用, 比如, 由于所谓的 Argument-dependent lookup (ADT),
!p
要求 T 的参数必须是完整类型.
如果 T 是 B 的派生类, 那么 std::unique_ptr<T>
是可以隐式转换成 std::unique_ptr<B>
的.
经过隐式转换后形成的 std::unique_ptr<B>
的默认删除器将会调用 B 自身的删除器 (delete
, 或者
delete[]
), 这将会导致未定义的行为 (undefined behavior),
除非 B 的析构函数是虚函数. 还应当注意的是,
std::shared_ptr 就不同了, 转换后的
std::shared_ptr<B>
将仍旧使用 T 的删除器, 不论 B
的析构是否为虚函数, 也会正确删除被占有对象.
不同于 std::shared_ptr, std::unique_ptr 能够通过任何满足 NullablePointer 的自定义句柄类型管理对象. 这就允许, 通过提供宏定义指针 boost::offset_ptr 或者其他奇特指针 (fancy pointer -- 提供指针抽象的指针) 的删除器, 来管理位于共享内存中的对象.
2. 示例
1 |
|
输出: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
171) Unique ownership semantics demo
D::D
D::bar
D::~D
2) Runtime polymorphism demo
D::D
D::bar
D::~D
3) Array form of unique_ptr demo
D::D
D::D
D::D
D::~D
D::~D
D::~D