一、实现原理
在智能指针对象中有一个裸指针,此指针存储的是动态创建对象的地址,用于生存期控制,能够确保智能指针对象离开所在作用域时,自动正确地销毁动态创建的对象,防止内存泄漏。
使用裸指针存在的问题:
(1)难以区分指针指向的是单个对象还是一组对象。
(2)使用完指针之后无法判断是否应该销毁指针,因为无法判断指针是否拥有指向的对象。
(3)在已经确定需要销毁指针的情况下,也无法确定是用delete关键字删除,还是有其他特殊的销毁机制。
二、auto_ptr
在C98标准中没有右值引用,也没有move,forward语义。
1、构造函数与析构函数
auto_ptr在构造时获取对某个对象的所有权,在析构时释放该对象。
2、拷贝构造与赋值
C98还没有加入右值引用,也没有move语义。
auto_ptr的拷贝构造和赋值重载陷入困境:
1、浅拷贝和浅赋值,指针重复释放。
2、深拷贝和深复制,语义矛盾。
auto_ptr要求其对裸指针的完全占有性。也就是说一个裸指针不能同时被两个以上的auto_ptr所拥有。那么在拷贝构造或赋值操作时,我们必须作特殊的处理来保证这个特性。auto_ptr的做法是所有权转移,即拷贝构造或赋值的原对象将失去对裸指针的所有权,所以,与一般拷贝构造函数,赋值函数不同,auto_ptr的拷贝构造函数,赋值函数的参数为引用而不是常引用。
当然,一个auto_ptr也不能同时拥有两个以上的裸指针,所以,拷贝或赋值的目标对象将先释放其原来所拥有的对象。
3、总结
auto_ptr主要有三大问题:
(1)复制和赋值会改变资源的所有权,不符合人的直觉。
(2)在STL容器中使用auto_ptr存在重大风险,因为容器内的元素必需支持可复制和可赋值。
(3)不支持对象数组的操作。
三、unique_ptr
1、unique_ptr分析和使用
unique_ptr是独占对象所有权语义的智能指针。
unique_ptr实现了独享被管理对象指针的概念,这意味着它可确保一个对象和其对应的资源同一时间只被一个unique_ptr对象拥有。一旦拥有者被销毁或者编程empty或者开始拥有另一个对象的地址,先前拥有的那个对象就会被销毁,其任何相应资源亦会被释放。
2、特点
(1)基于排他所有权模式:两个指针不能指向同一个资源。
(2)由于独占对象的拥有权,所以不提供拷贝构造函数和左值赋值函数重载。
(3)提供移动构造和移动赋值函数。
(4)为了实现单个对象和一组对象的管理,添加了删除器类型。
四、shared_ptr
1、shared_ptr分析和使用
shared_ptr实现了共享所有权方式来管理资源对象,这意味没有一个特定的shared_ptr拥有资源对象。相反,这些指向同一个资源对象的shared_ptr相互协作来确保资源对象在不需要的时候被析构。
2、特点
(1)基于共享所有权模式:多个指针能够同时指向同一个资源。
(2)基于共享所有权,使用引用计数控制块管理资源对象的生命期。
(3)提供拷贝构造函数和赋值重载函数;提供移动构造和移动赋值函数。
(4)为了实现单个对象和一组对象的管理,添加了删除器类型。
3、引用计数器的作用
(1)当新的shared_ptr对象与资源对象的地址关联时,则在其构造函数中,将与此资源对象关联的引用计数加1.
(2)当任何shared_ptr对象超出作用域时,则在其析构函数中,将与资源对象关联的引用计数减1.如果引用计数变为0,则表示没有其他shared_ptr对象与此资源对象关联,在这种情况下,它使用deleter删除器删除该资源对象。
五、weak_ptr
1、weak_ptr分析和使用
弱引用指引weak_ptr是用来监视shared_ptr的生命周期,是shared_ptr的一个助手。weak_ptr没有重载操作符*和->,因为它不与shared_ptr共享指针,不能操作资源,主要是通过shared_ptr获得资源的检测权,它的构造不会增加引用计数,它的析构也不会减少引用计数,纯粹只是作为一个旁观者来监视shared_ptr中管理的资源是否存在。weak_ptr还可以用来返回this指针和解决循环引用的问题。
2、weak_ptr构建
当我们创建一个weak_ptr时,需要用一个shared_ptr实例来初始化weak_ptr,由于是弱共享,weak_ptr的创建并不会影响shared_ptr的引用计数值。可以通过use_count()方法来获得观测资源的引用计数。
3、通过expired()方法来判断所观测的资源是否已经被释放
4、通过lock()方法来获取所监视的shared_ptr
weak_ptr并没有重载operator->和operator*操作符,因此不可直接通过weak_ptr使用对象,典型的用法是调用其lock函数来获得shared_ptr实例,进而访问对象。