智能指针
智能指针 c++11
std::unique_ptr<T>
:独占资源所有权的指针。
当我们独占资源的所有权的时候,可以使用 std::unique_ptr 对资源进行管理——离开 unique_ptr 对象的作用域时,会自动释放资源。
std::unique_ptr 是 move-only 的。
1 | std::unique_ptr<int> uptr = std::make_unique<int>(200); |
std::unique_ptr 可以指向一个数组。
可以自定义 deleter。
1 | { |
1 | { |
std::shared_ptr<T>
:共享资源所有权的指针。
其实就是对资源做引用计数——当引用计数为 0 的时候,自动释放资源。
1 | { |
也可以指向数组和自定义 deleter。
1 | { |
一个 shared_ptr 对象的内存开销要比裸指针和无自定义 deleter 的 unique_ptr 对象略大。
shared_ptr 需要维护的信息有两部分:
- 指向共享资源的指针。
- 引用计数等共享资源的控制信息——实现上是维护一个指向控制信息的指针。
所以,shared_ptr 对象需要保存两个指针。shared_ptr 的 的 deleter 是保存在控制信息中,所以,是否有自定义 deleter 不影响 shared_ptr 对象的大小。
不能去掉 shared_ptr 对象中指向共享资源的指针。 因为 shared_ptr 对象中的指针指向的对象不一定和控制块中的指针指向的对象一样。(由于多态的存在,有可能指向父类对象)。
1 | struct Fruit { |
std::shared_ptr 支持 aliasing constructor。
Aliasing constructor,简单说就是构造出来的 shared_ptr 对象和参数 r 指向同一个控制块(会影响 r 指向的资源的生命周期),但是指向共享资源的指针是参数 ptr。看下面这个例子。
1 | using Vec = std::vector<int>; |
使用 std::shared_ptr 时,会涉及两次内存分配:一次分配共享资源对象;一次分配控制块。C++ 标准库提供了 std::make_shared 函数来创建一个 shared_ptr 对象,只需要一次内存分配。
这种情况下,不用通过控制块中的指针,我们也能知道共享资源的位置——这个指针也可以省略掉。
成员函数获取 this 的 shared_ptr 的正确的做法是继承 std::enable_shared_from_this。
1 | class Bar : public std::enable_shared_from_this<Bar> { |
一般情况下,继承了 std::enable_shared_from_this 的子类,成员变量中增加了一个指向 this 的 weak_ptr。这个 weak_ptr 在第一次创建 shared_ptr 的时候会被初始化,指向 this。
似乎继承了 std::enable_shared_from_this 的类都被强制必须通过 shared_ptr 进行管理。如果没有创建shared_ptr 直接调用shared_from_this()方法,将会报错。
std::weak_ptr<T>
:共享资源的观察者,需要和 std::shared_ptr 一起使用,不影响资源的生命周期。
std::weak_ptr 要与 std::shared_ptr 一起使用。 一个 std::weak_ptr 对象看做是 std::shared_ptr 对象管理的资源的观察者,它不影响共享资源的生命周期:
- 如果需要使用 weak_ptr 正在观察的资源,可以将 weak_ptr 提升为 shared_ptr。
- 当 shared_ptr 管理的资源被释放时,weak_ptr 会自动变成 nullptr。
1 | void Observe(std::weak_ptr<int> wptr) { |
当 shared_ptr 析构并释放共享资源的时候,只要 weak_ptr 对象还存在,控制块就会保留,weak_ptr 可以通过控制块观察到对象是否存活。