c++中智能指针的作用是非常大的,它不仅能解决很多裸指针带来的内存相关问题,还能用来管理资源(RAII)。
c++中的智能指针有很多种,其中以shared_ptr和weak_ptr最为重要(个人观点),掌握了这两个智能指针的原理,其它的就很好理解了。
shared_ptr是典型的引用计数型智能指针,相信很多c++程序员都写过功能类似的智能指针类。很多时候用这个指针就足够了。
但是有些情况下,shared_ptr可能产生循环引用, 比如Observer模式中,或者父子关系的对象等。为了解决循环引用而造成的内存泄露,引入了weak_ptr。
shared_ptr是strong reference, weak_ptr是weak reference。shared_ptr保证所持有的raw指针是有效的,而weak_ptr则不能保证所持有的指针是否还指向一个有效的对象。
在需要访问所持有的指针的时候,调用weak_ptr的expired或者lock就能判断出是否能得到对应的shared_ptr。
本文的目的不是为了介绍shared_ptr和weak_ptr的使用方法,而是为了介绍它们的实现原理,更主要的是为了说明weak_ptr是如何知道是否还有shared_ptr对象存在的。
还有一些关于它们使用习惯或注意点的说明。
一、shared_ptr
- ref_count / control block (控制块)
在典型的实现中,std::shared_ptr 只保存两个指针:
- 指向被管理对象的指针
- 指向控制块(control block)的指针
控制块是一个动态分配的对象,其中包含:
- 指向被管理对象的指针或被管理对象本身
- 删除器
- 分配器(allocator)
- 拥有被管理对象的
shared_ptr
的数量 - 引用被管理对象的
weak_ptr
的数量
通过 std::make_shared 和 std::allocate_shared 创建 shared_ptr
时,控制块将被管理对象本身作为其数据成员;而通过构造函数创建 shared_ptr
时则保存指针。
class _Ref_count_base { // common code for reference countingprivate:virtual void _Destroy () = 0 ;virtual void _Delete_this () = 0 ;
long _Uses ;long _Weaks ;
protected:_Ref_count_base () : _Uses ( 1 ), _Weaks ( 1 ) { // construct}...};template < class _Ty > class _Ref_count : public _Ref_count_base {};template < class _Ty , class _Dx > class _Ref_count_del : public _Ref_count_base {};template < class _Ty ,class _Dx ,class _Alloc >class _Ref_count_del_alloc: public _Ref_count_base {};
_Ty * _Ptr ;_Ref_count_base * _Rep ;