智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。新标准库提供的两种智能指针的区别在于管理底层指针的方式:shared_ptr
允许多个指针指向同一个对象;unique_ptr
则独占所指向的对象。标准库定义的weak_ptr
伴随类,是一种弱引用,它指向shared_ptr
所管理的对象。
1.shared_ptr
shared_ptr 和 unique_ptr都支持的操作:
- shared_ptr< T > sp、unique_ptr< T > up: 指向类型为T的对象
- p: 用作一个条件判断,若p指向一个对象,则为true
- *p: 解引用p,获得它指向的对象
- p->mem: 等价于(*p).mem
- p.get(): 返回p中保存的指针。要小心使用,若智能指针释放了其对象,返回的指针所指向的对象也就消失了
- swap(p, q)、p.swap(q): 交换p和q
shared_ptr 独有操作:
- make_shared< T >(args): 返回一个shared_ptr,指向一个动态分配的类型为T的对象。使用args初始化此对象
- shared_ptr< T >p(q): p是shared_ptr q 的拷贝;此操作会递增q中的计数器。q 中的指针必须能转换为T*
- p = q: p 和 q 都是shared_ptr,所保存的指针必须能相互转换。此操作会递增q的引用计数,递减p的引用计数;若p的引用计数变为0,则将其管理的原内存释放
- p.unique(): 若p.use_count() 为1,返回true;否则返回false
- p.use_count(): 返回与p共享对象的智能指针数量;可能很慢,主要用于调试
1.1 shared_ptr 和 new 结合使用
- 接受指针参数的智能指针的构造函数时explicit的。因此必须使用直接初始化的形式:
shared_ptr< int > p1 = new int(1024); // 错误:必须使用直接初始化
shared_ptr< int > p2(new int(1024)); // 正确:使用了直接初始化形式 - 不要混合使用普通指针和智能指针…: shared_ptr 可以协调对象的析构,但这仅限于其自身的拷贝(shared_ptr之间的拷贝)。
- 也不要使用get初始化另一个智能指针或为智能指针赋值: 只能在确定代码不会delete指针的情况下,才能使用get。特别是,永远不要使用get初始化另一个智能指针或者为另一个智能指针赋值。
- 定义和改变shared_ptr的其它方法:
- shared_ptr< T > p(u): p从unique_ptr u 那里接管了对象的所有权;将u置为空
- shared_ptr< T > p(q, d): p接管了内置指针q所指向的对象的所有权。q必须能转换为T* 类型。p将使用可调用对象d来代替delete
- shared_ptr< T > p(p2, d): p 是 shared_ptr p2 的拷贝,p将用可调用对象d来代替delete
- p.reset()、p.reset(q)、p.reset(q, d): 若p是唯一指向其对象的shared_ptr,reset 会释放此对象。若传递了可选参数内置指针q,会令p指向q,否则会将p置为空。若还传递了参数d,将会调用d而不是delete来释放q