【C++11】智能指针.md
C++11中有哪几种智能指针
auto_ptr
shared_ptr
scope_ptr
简单介绍auto_ptr
- auto_ptr是一个可以根据其自己指向的内容自动确定类型的指针
- auto_ptr在aos代码中用得比较多
- 使用auto_ptr需要包含
#include <memory>
头文件
简单介绍shared_ptr
- 通过指针保持对某个对象共享拥有权的智能指针。若干个shared_ptr对象可以拥有同一个对象,最后一个指向该对象的shared_ptr被销毁或者重置时,该对象被销毁。销毁该对象时使用的是delete 表达式,或者是在构造shared_ptr时传入的自定义删除器。
使用auto_ptr需要注意的地方
- auto_ptr 类可以用于管理由 new 分配的单个对象,但是无法管理动态分配的数组(我们通常不会使用数组,而是使用 vector 代替数组)。
- auto_ptr 在拷贝和赋值的时候有不寻常的行为,因此 auto_ptrs 不能被保存在 stl 的容器中。当 auto_ptr 离开了自己的作用域或者被销毁,由 auto_ptr 管理的对象也会被销毁。
复用一个智能指针
- 使用auto_ptr的reset()函数来重置auto_ptr使之拥有另一个对象。
- 如果这个auto_ptr已经拥有了一个对象,那么,它会先删除已经拥有的对象,因此调用reset()就如同销毁这个auto_ptr,然后新建一个并拥有一个新对象:
void h()
{
auto_ptr<T> pt( new T(1) );
// 即pt会首先delete pt目前指向的地址(new T(1)得到的地址),然后再指向new T(2)分配的地址
pt.reset( new T(2) );
}
进一步了解shared_ptr:
- boost::shared_ptr的管理机制其实并不复杂,就是对所管理的对象进行了引用计数,当新增一个boost::shared_ptr对该对象进行管理时,就将该对象的引用计数加一;减少一个boost::shared_ptr对该对象进行管理时,就将该对象的引用计数减一,如果该对象的引用计数为0的时候,说明没有任何指针对其管理,才调用delete释放其所占的内存。
- shared_ptr是线程安全的,这在多线程程序中非常重要
- shared_ptr可以使用在stl容器中
- boost::shared_ptr并不是绝对安全,下面几条规则能使我们更加安全的使用boost::shared_ptr:
- 避免对shared_ptr所管理的对象的直接内存管理操作,以免造成该对象的重释放
- shared_ptr并不能对循环引用的对象内存自动管理(这点是其它各种引用计数管理内存方式的通病)。
- 不要构造一个临时的shared_ptr作为函数的参数。
一段可能导致内存泄露的shared_ptr使用代码
void test()
{
foo(boost::shared_ptr<implementation>(new implementation()),g());
}
// 上面的代码如何造成了内存泄露
正确的用法为:
void test()
{
boost::shared_ptr<implementation> sp(new implementation());
foo(sp,g());
}
shared_ptr实现说明
在典型的实现中,std::shared_ptr 只保存两个指针:
指向被管理对象的指针
指向控制块(control block)的指针
控制块是一个动态分配的对象,其中包含:
指向被管理对象的指针或被管理对象本身
删除器
分配器(allocator)
拥有被管理对象的 shared_ptr 的数量
引用被管理对象的 weak_ptr 的数量
通过 std::make_shared 和 std::allocate_shared 创建 shared_ptr 时,控制块将被管理对象本身作为其数据成员;而通过构造函数创建 shared_ptr 时则保存指针。
shared_ptr 持有的指针是通过 get() 返回的;而控制块所持有的指针/对象则是最终引用计数归零时会被删除的那个。两者并不一定相等。
shared_ptr 的析构函数会将控制块中的 shared_ptr 计数器减一,如果减至零,控制块就会调用被管理对象的析构函数。但控制块本身直到 std::weak_ptr 计数器同样归零时才会释放。