shared_ptr代码研究
迪丽瓦拉
2024-05-06 19:04:00
0

个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

注:研究代码是在windows上vs2015中的实现

引言

shared_ptr被使用的很广泛,许多经典库使用share_ptr作为实现函数的接口类型使用,确实还是很有必要仔细研究一下;
下面就从代码层来看一看shared_ptr的数据结构情况。

一:代码研究

1. shared_ptr继承自_Ptr_base

// CLASS TEMPLATE shared_ptr
template
class shared_ptr : public _Ptr_base<_Ty> 
{...}

2._Ptr_base是一个基类,没有继承;_Ptr_base含有两个指针元素,一个指向元素,一个指向计数类;

// CLASS TEMPLATE _Ptr_base
template
class _Ptr_base
{
...
private:element_type * _Ptr{nullptr};_Ref_count_base * _Rep{nullptr};
...
}

3. shared_ptr中,通过new 方法生成计数类对象

_Set_ptr_rep_and_enable_shared(_Px, new _Ref_count<_Ux>(_Px));
_Set_ptr_rep_and_enable_shared(_Px, new _Ref_count_resource<_UxptrOrNullptr, _Dx>(_Px, _STD move(_Dt)));
using _Refd = _Ref_count_resource_alloc<_UxptrOrNullptr, _Dx, _Alloc>;

4. _Ref_count_base是一个基类,无继承;_Ref_count_base有两个atomic元素,一个是_Uses, 一个是_Weaks;

// CLASS _Ref_count_base
class __declspec(novtable) _Ref_count_base
{
..._Atomic_counter_t _Uses;_Atomic_counter_t _Weaks;_Ref_count_base() : _Uses(1), _Weaks(1)	// non-atomic initializations{// construct}
...
}

5._Ref_count继承自_Ref_count_base;并有了一个指针元素,_Ptr,指向了计数的元素;

template
class _Ref_count : public _Ref_count_base
{
..._Ty * _Ptr;virtual void _Destroy() noexcept override{	// destroy managed resourcedelete _Ptr;}
...
}

6._Ref_count_resource也继承自_Ref_count_base;并有了一个_Compressed_pair元素,pair中一个是default_delete函数,一个是元素指针;

template
class _Ref_count_resource : public _Ref_count_base
{
..._Compressed_pair<_Dx, _Resource> _Mypair;virtual void _Destroy() noexcept override{	// destroy managed resource_Mypair._Get_first()(_Mypair._Get_second());}
...
}

二:share_ptr综述

基于上面的代码跟踪分析,可以看出share_ptr构建时:

  • 会构建出两个指针,一个用来指向维护的元素,一个用来指向元素的计数管理类对象;
  • 看到计数类使用的计数对象是atomic类型的,所以这个计数是可以跨线程保证计数操作原子性,也即能保证线程安全;
  • 还看到计数类中有元素的指针,这个保证了计数对象可以脱离shared_ptr对象而存在,保证了shared_ptr在做数据转移时,计数对象不会丢失指向;

另外为什么shared_ptr经常会被一些流行库用作接口类型呢?

  • 一方面作为智能指针,解决了申请内存释放处理,传递过程中不用担心未被释放;
  • 另一方面shared_ptr的内部数据结构很简单,只有两个指针,shared_ptr作为参数传递时,开销很小;

三:结合make_shared一块来看

另外结合make_shared一块来看这个shared_ptr的话,也能看出直接使用make_shared的话,实际采用的是计数和对象绑定的计数类:

// FUNCTION TEMPLATE make_shared
template
_NODISCARD inline shared_ptr<_Ty> make_shared(_Types&&... _Args)
{// make a shared_ptrconst auto _Rx = new _Ref_count_obj<_Ty>(_STD forward<_Types>(_Args)...);shared_ptr<_Ty> _Ret;_Ret._Set_ptr_rep_and_enable_shared(_Rx->_Getptr(), _Rx);return (_Ret);
}

因为是捆绑申请,内存在一起的,所以就不能分别释放,而是只能在一起释放;从_Ref_count_obj的_Destory函数中就可以看出来,它只调用资源的析构函数,并不去做delete操作的。

template
class _Ref_count_obj	: public _Ref_count_base{virtual void _Destroy() noexcept override{	// destroy managed resource_Getptr()->~_Ty();}virtual void _Delete_this() noexcept override{	// destroy selfdelete this;}...
}

个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

相关内容