shared_ptr的内部实现原理

    本文先分析shared_ptr的内部实现原理,然后实例演示shared_ptr的使用。

1. 实现原理

    shared_ptr的定义如下:

template
class shared_ptr : public _Ptr_base<_Ty>

    shared_ptr从基类_Ptr_base 继承了如下成员变量(部分源码):

template
class _Ptr_base
{
private:element_type * _Ptr{ nullptr };      //指向资源_Ref_count_base * _Rep{ nullptr };   //指向资源引用计数
}

   其中,_Ptr指向资源,_Rep指向资源引用计数。

    _Ref_count_base的定义如下:

class __declspec(novtable) _Ref_count_base
{	// common code for reference counting
private:_Atomic_counter_t _Uses;   //记录了引用资源的shared_ptr的个数_Atomic_counter_t _Weaks;  //记录了weak_ptr的个数
}

    其中,Uses记录了资源的引用计数,也就是引用资源的shared_ptr 的个数;_Weaks记录了weak_ptr的个数,相当于资源观察者的个数。

    shared_ptr的构造函数定义如下:

template, _Can_array_delete<_Ux>, _Can_scalar_delete<_Ux>>,_SP_convertible<_Ux, _Ty>>, int> = 0>explicit shared_ptr(_Ux * _Px)
{	// construct shared_ptr object that owns _Px_Setp(_Px, is_array<_Ty>{});
}template
void _Setp(_Ux * _Px, false_type)
{	// take ownership of _Px_TRY_BEGIN	// allocate control block and set_Set_ptr_rep_and_enable_shared(_Px, new _Ref_count<_Ux>(_Px));_CATCH_ALL	// allocation failed, delete resourcedelete _Px;_RERAISE;_CATCH_END
}

    shared_ptr的构造函数中会开辟新的引用计数的资源

    shared_ptr的拷贝构造函数定义如下:

shared_ptr(const shared_ptr& _Other) noexcept
{	// construct shared_ptr object that owns same resource as _Otherthis->_Copy_construct_from(_Other);
}template
void _Copy_construct_from(const shared_ptr<_Ty2>& _Other)
{	// implement shared_ptr's (converting) copy ctorif (_Other._Rep){_Other._Rep->_Incref();}_Ptr = _Other._Ptr;_Rep = _Other._Rep;
}

    shared_ptr的拷贝构造函数没有开辟新的引用计数的资源,只是引用计数加1。

2.代码实例    

    先看下面出错的例子:

#include 
#include 
using namespace std;
int main()
{// 裸指针指向堆上的对象int *p = new int;       shared_ptr ptr1(p);shared_ptr ptr2(p);//两次打印都是1,析构两次,出错cout << "use_count = " <<  ptr1.use_count() << endl;cout << "use_count = " << ptr2.use_count() << endl;getchar();return 0;
}

    执行结果:

  

    原因:ptr1(p) 和 ptr2(p)都调用了shared_ptr的构造函数,它们管理同一个资源,但是重新开辟了引用计数的资源。所以引用计数都为1。析构函数会被调用两次,所以程序出错。

    正确的代码如下:

#include 
#include 
using namespace std;
int main()
{// 裸指针指向堆上的对象int *p = new int;       shared_ptr ptr1(p);shared_ptr ptr2(ptr1);//两次打印都是2,析构一次,正确cout << "use_count = " <<  ptr1.use_count() << endl;cout << "use_count = " << ptr2.use_count() << endl;getchar();return 0;
}

    执行结果:

    原因:ptr1(p) 调用构造函数,ptr2(ptr1)调用拷贝构造函数(没有开辟新的引用计数的资源,只是引用计数加1)。析构函数会被调用一次,所以程序正确。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部