发展历史
C++98中产生了第一个智能指针auto_ptr;
C++boost给出了更实用的scoped_ptr和shared_ptr和weak_ptr;
C++TR1,引入了shared_ptr等,不过TR1并不是标准版;
C++11引入了unique_ptr和shared_ptr和weak_ptr。需要注意的是unique_ptr对应boost的scoped_ptr,并且这些智能指针的实现原理是参考boost中的实现的。
RAII
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此我们实际上把一份资源的责任托管给了一个对象。这种做法有两大好处:
不需要显式地释放资源;
采用这种方式,对象所需的资源在其生命期内始终保持有效;
各个版本智能指针的特点
auto_ptr
管理权转移思想,是一个失败设计
unique_ptr
简单粗暴,防拷贝,独占对象的所有权,由于没有引用计数,性能较好。可以通过std::move来转移到其他的unique_ptr。
shared_ptr
通过引用计数的方式来实现多个shared_ptr对象之间共享资源:
shared_ptr在其内部,给每个资源都维护了一份计数,用来记录该份资源被几个对象共享;
在对象被销毁时(也就是洗后函数调用),就说明自己不适用该资源了,对象的引用计数减一;
如果引用计数时0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。
共享对象的所有权,但性能略差。
如果希望只有一个智能指针管理资源或者管理数组就用unique_ptr,如果希望多个智能指针管理同一个资源就用shared_ptr。
weak_ptr
weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的shared_ptr, weak_ptr只是提供了对管理对象的一个访问手段。
weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。
什么是循环引用?怎么解决?
share_ptr虽然已经很好用了,但是有一点share_ptr智能指针还是有内存泄露的情况,当两个对象相互使用一个shared_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄漏。
循环引用发生在两个或多个shared_ptr实例相互引用,形成一个闭环时。因为每个 shared_ptr 在被销毁之前都会检查其引用计数,只有当引用计数为零时才会释放对象,所以循环引用会导致对象无法被释放,即使没有其他外部引用指向它。
weak_ptr配合share_ptr,解决循环引用问题。可以在一个类中使用weak_ptr来引用另一个类的实例,从而打破循环引用。