C++11里shared_ptr源码剖析

来源:互联网 发布:图像算法工程师容易吗? 编辑:程序博客网 时间:2024/06/03 19:07

很多人不知道引用计数放在哪,昨天为止我也不知道,O(∩_∩)O哈哈~

A *a = new A;shared_ptr<A> sp(a);

上面代码发生了什么呢?
进入shared_ptr的构造函数

template<class _Ux>    explicit shared_ptr(_Ux *_Px){        _Resetp0(_Px, new _Ref_count<_Ux>(_Px));//这里是new出来的_Ref_count    }

1.shared_ptr继承_Ptr_base
2.Ptr_base里面有两个东西

private:    _Ty *_Ptr;    _Ref_count_base *_Rep;  

一个是指向传进来的地址,一个是_Ref_count_base(用于保存引用计数,并且和week_ptr交流的一个类)基类是_Ref_count_base,引用计数就在基类里面

private:    _Atomic_counter_t _Uses;    _Atomic_counter_t _Weaks;   

3.然后调用_Resetp0

template<class _Ux>void _Resetp0(_Ux *_Px, _Ref_count_base *_Rx){       this->_Reset0(_Px, _Rx);    _Enable_shared(_Px, _Rx);}

4.然后调用_Reset0

void _Reset0(_Ty *_Other_ptr, _Ref_count_base *_Other_rep){   //释放资源 and 利用新资源    if (_Rep != 0)        _Rep->_Decref();//如果原来有资源,释放原来的资源    _Rep = _Other_rep;    _Ptr = _Other_ptr;}

5.把上面new的_Ref_count<_Ux>(_Px)赋值给_Ptr_base里面的_Ptr
把传进来的指针赋值给_Ptr
6.这样share_ptr里面就有一个_Ref_count了,这个_Ref_count在初始化的时候会把两个引用计数都赋值为1

_Ref_count_base(){    _Init_atomic_counter(_Uses, 1);    _Init_atomic_counter(_Weaks, 1);}

为啥weeks是1呢?不应该是0么?
因为在析构的时候weeks计数器是先减一再判断为不为0

// decrement weak reference countif (_MT_DECR(_Mtx, _Weaks) == 0)        delete this;

很重要★★★★因为shared和weak都是共用一个_Ref_count_base
当所有的week_ptr都没了才释放自己,不然之后week访问这个类就会出错

有点晕?看幅图

这里写图片描述

下面是我精简后的源码,可以更好加深理解

template<class _Ty>class _Ptr_base{public:    _Ptr_base(): _Ptr(0), _Rep(0){}    long use_count()    {   // _Ref_count_base 存在就返回用户的引用个数 为NULL就返回0        return (_Rep ? _Rep->_Use_count() : 0);    }    void _Reset0(_Ty *_Other_ptr, _Ref_count_base *_Other_rep)    {   //释放资源 and 利用新资源        if (_Rep != 0)            _Rep->_Decref();//如果原来有资源,释放原来的资源        _Rep = _Other_rep;        _Ptr = _Other_ptr;    }    ///////////////////赋值/////////////////////////    shared_ptr(const _Myt& _Other) _NOEXCEPT    {           _Reset(_Other._Ptr, _Other._Rep);    }    void _Reset(_Ty *_Other_ptr, _Ref_count_base *_Other_rep)    {   // release resource and take _Other_ptr through _Other_rep        if (_Other_rep)            _Other_rep->_Incref();//这里会把_Ref_count_base里面的_Uses + 1        _Reset0(_Other_ptr, _Other_rep);    }    //资源释放    void _Decref(){        if (_Rep != 0)            _Rep->_Decref();    }private:    _Ty *_Ptr;    _Ref_count_base *_Rep;  };
template<class _Ty>class shared_ptr: public _Ptr_base<_Ty>{public:    template<class _Ux>    explicit shared_ptr(_Ux *_Px){        _Resetp0(_Px, new _Ref_count<_Ux>(_Px));//这里是new出来的_Ref_count    }private:    template<class _Ux>    void _Resetp(_Ux *_Px)    {   // release, take ownership of _Px        _Resetp0(_Px, new _Ref_count<_Ux>(_Px));    }    template<class _Ux>    void _Resetp0(_Ux *_Px, _Ref_count_base *_Rx)    {           this->_Reset0(_Px, _Rx);        _Enable_shared(_Px, _Rx);    }    ~shared_ptr() _NOEXCEPT    {   // release resource        this->_Decref();    }};
class _Ref_count_base{protected:    _Ref_count_base()    {   // construct        _Init_atomic_counter(_Uses, 1);        _Init_atomic_counter(_Weaks, 1);    }    void _Decref()    {   // uses - 1 等于0 就是放资源        if (_MT_DECR(_Mtx, _Uses) == 0)        {   // destroy managed resource, decrement weak reference count            delete _Ptr;//直接delete            // decrement weak reference count            if (_MT_DECR(_Mtx, _Weaks) == 0)//很重要★★★★因为shared和weak都是共用一个_Ref_count_base                delete this;//当所有的week_ptr都没了才释放自己,不然week访问这个类就会出错        }    }private:    _Atomic_counter_t _Uses;    _Atomic_counter_t _Weaks;   };
template<class _Ty>class _Ref_count: public _Ref_count_base{   // handle reference counting for object without deleterpublic:    _Ref_count(_Ty *_Px): _Ref_count_base(), _Ptr(_Px){}private:    virtual void _Destroy()    {        delete _Ptr;    }    virtual void _Delete_this()    {   // destroy self        delete this;    }    _Ty * _Ptr;};
原创粉丝点击