VS 2010 shared_ptr 源码分析

类结构框架

下面这张图来自于网络,已不知原作者。这张图表明了shared_ptr类结构图

_Ref_count_base是在shared_ptr创建的时候new出来的。_Ref_count_base有3个子类,分别对应shared_ptr构造时的3种形式。在shared_ptr的实现中,会根据调用的shared_ptr构造函数的不同,使用不同类型的_Ref_count_base创建。_Ref_count_base中保存了两个引用计数: 
 _Uses:用于shared_ptr,表示该_Ref_count_base被几个shared_ptr引用了。当_Uses等于0时,会释放_Ref_count_base中保存的对象(也就是用户传入的指针)。
_Weaks:用于weak_ptr,表示该_Ref_count_base被几个weak_ptr引用了。当_ Weaks等于0时,会释放_Ref_count_base自身。
有了这两个引用计数,就能实现智能指针管理资源基本功能以及野指针检查的功能。

// CLASS _Ref_count_base
class _Ref_count_base
	{	// common code for reference counting
private:
	virtual void _Destroy() = 0;
	virtual void _Delete_this() = 0;

	long _Uses;
	long _Weaks;

protected:
	_Ref_count_base()
		: _Uses(1), _Weaks(1)
		{	// construct
		}

public:
	virtual ~_Ref_count_base()
		{	// ensure that derived classes can be destroyed properly
		}

	bool _Incref_nz()
		{	// increment use count if not zero, return true if successful
		for (; ; )
			{	// loop until state is known
			long _Count = (volatile long&)_Uses;
			if (_Count == 0)
				return (false);
			if (_MT_CMPX(_Uses, _Count + 1, _Count) == _Count)
				return (true);
			}
		}

	void _Incref()
		{	// increment use count
		_MT_INCR(_Mtx, _Uses);
		}

	void _Incwref()
		{	// increment weak reference count
		_MT_INCR(_Mtx, _Weaks);
		}

	void _Decref()
		{	// decrement use count
		if (_MT_DECR(_Mtx, _Uses) == 0)
			{	// destroy managed resource, decrement weak reference count
			_Destroy();
			_Decwref();
			}
		}

	void _Decwref()
		{	// decrement weak reference count
		if (_MT_DECR(_Mtx, _Weaks) == 0)
			_Delete_this();
		}

	long _Use_count() const
		{	// return use count
		return (_Uses);
		}

	bool _Expired() const
		{	// return true if _Uses == 0
		return (_Uses == 0);
		}

	virtual void *_Get_deleter(const _XSTD2 type_info&) const
		{	// return address of deleter object
		return (0);
		}
	};
	// TEMPLATE CLASS _Ref_count, _Ref_count_del, _Ref_count_del_alloc
template<class _Ty>
	class _Ref_count
	: public _Ref_count_base
	{	// handle reference counting for object without deleter
public:
	_Ref_count(_Ty *_Px)
		: _Ref_count_base(), _Ptr(_Px)
		{	// construct
		}
private:
	virtual void _Destroy()
		{	// destroy managed resource
		delete _Ptr;
		}

	virtual void _Delete_this()
		{	// destroy self
		delete this;
		}

	_Ty * _Ptr;
	};

原理

记得早些年间看《C++ Primer Plus》里面讲到类的静态(static)成员变量的时候,举得例子大概就是说:有一个类MyClass,此类中有一个static变量m_nCount,然后再类的构造函数中将m_nCount+1,再析构函数中将m_nCount-1,那么所有MyClass的对象数量就可以使用m_nCount来表示。我想这里的思想与shared_ptr有异曲同工之妙。在所有的shared_ptr中,都共享同一个_Ref_count_base,在_Ref_count_base中记录着一个_Uses,用以代表shared_ptr的个数。每构造一个shared_ptr,_Uses +1,析构一个shared_ptr,_Uses-1。当然除了第一个shared_ptr是直接引用原生指针之外,其他的shared_ptr必须是由之前的shared_ptr赋值或复制得来的。

 

从构造说起

有如下一行代码

shared_ptr<int> pa(new int(11));
	template<class _Ux>
		explicit shared_ptr(_Ux *_Px)
		{	// construct shared_ptr object that owns _Px
		_Resetp(_Px);
		}

下面代码有一处代码 :new _Ref_count<_Ux>(_Px),当第一个对某指针A引用的shared_ptr创建的时候,会在堆上生成_Ref_coun对象。

	template<class _Ux>
		void shared_ptr::_Resetp(_Ux *_Px)
		{	// release, take ownership of _Px
		_TRY_BEGIN	// allocate control block and reset
		_Resetp0(_Px, new _Ref_count<_Ux>(_Px));
		_CATCH_ALL	// allocation failed, delete resource
		delete _Px;
		_RERAISE;
		_CATCH_END
		}
_Ref_count::_Ref_count(_Ty *_Px)
		: _Ref_count_base(), _Ptr(_Px)
		{	// construct
		}

 所以对指针A引用的shared_ptr都共用一个_Ref_count,当然在第一次创建_Ref_count的时候,_Uses肯定设为1,毕竟已经有一个shared_ptr引用指针A了。

_Ref_count_base::_Ref_count_base()
		: _Uses(1), _Weaks(1)
		{	// construct
		}
	template<class _Ux>
		void shared_ptr::_Resetp0(_Ux *_Px, _Ref_count_base *_Rx)
		{	// release resource and take ownership of _Px
		this->_Reset0(_Px, _Rx);
		_Enable_shared(_Px, _Rx);
		}
	void _Ptr_base::_Reset0(_Ty *_Other_ptr, _Ref_count_base *_Other_rep)
		{	// release resource and take new resource
		if (_Rep != 0)
			_Rep->_Decref();
		_Rep = _Other_rep;//设置_Rep
		_Ptr = _Other_ptr;//设置_Ptr
		}

多个shared_ptr共享同一个变量

shared_ptr<int> pb = pa;
	shared_ptr(const _Myt& _Other)
		{	// construct shared_ptr object that owns same resource as _Other
		this->_Reset(_Other);
		}
	template<class _Ty2>
		void _Ptr_base::_Reset(const _Ptr_base<_Ty2>& _Other)
		{	// release resource and take ownership of _Other._Ptr
		_Reset(_Other._Ptr, _Other._Rep, false);
		}
	void _Ptr_base::_Reset(_Ty *_Other_ptr, _Ref_count_base *_Other_rep, bool _Throw)
		{	// take _Other_ptr through _Other_rep from weak_ptr if not expired
			// otherwise, leave in default state if !_Throw,
			// otherwise throw exception
        //将我们被复制的那个_Other_rep的_Uses+1,然后再将_Other_rep与它的所引用指针复制到this
		if (_Other_rep && _Other_rep->_Incref_nz())
			_Reset0(_Other_ptr, _Other_rep);
		else if (_Throw)
			_THROW_NCEE(bad_weak_ptr, 0);
		}
    #define _MT_CMPX(x, y, z)	_InterlockedCompareExchange(&x, y, z)
	bool _Incref_nz()
		{	// increment use count if not zero, return true if successful
		for (; ; )
			{	// loop until state is known 
			long _Count = (volatile long&)_Uses;
			if (_Count == 0)
				return (false);
            //把_Uses+1,循环的原因是怕失败,失败的原因是因为锁?
			if (_MT_CMPX(_Uses, _Count + 1, _Count) == _Count)
				return (true);
			}
		}

weak_ptr

将一个weak_ptr绑定到一个shared_ptr s_p ,不会增加s_p的引用计数。

weak_ptr<int> w_p(pa);

进入构造函数

	template<class _Ty2>
		weak_ptr(const shared_ptr<_Ty2>& _Other,
			typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
				void *>::type * = 0)//第二个个参数真是恶心,先不管
		{	// construct weak_ptr object for resource owned by _Other
		this->_Resetw(_Other);
		}

进入基类_Ptr_base里 

	template<class _Ty2>
		void _Resetw(const _Ptr_base<_Ty2>& _Other)
		{	// release weak reference to resource and take _Other._Ptr
		_Resetw(_Other._Ptr, _Other._Rep);
		}
	template<class _Ty2>
        //第一个参数就是原生指针,第二个参数就是shared_ptr的基类里的_Ref_count_base *_Rep;
        //当然啦,weak_pte也有一个_Ref_count_base *_Rep和我们引用的shared_ptr共用一个
        //_Ref_count_base ;_Ref_count_base 里有shared_ptr引用
        //计数与weak_ptr引用计数,参照我们上面的图
		void _Resetw(_Ty2 *_Other_ptr, _Ref_count_base *_Other_rep)
		{	// point to _Other_ptr through _Other_rep
		if (_Other_rep)
			_Other_rep->_Incwref();//增加weak_ptr引用计数
		if (_Rep != 0)//若此weak_ptr之前有引用某shared_ptr,将之前的weak_ptr引用计数减一
			_Rep->_Decwref();
		_Rep = _Other_rep;//此weak_ptr与引用的shared_ptr共用一个_Ref_count_base 
		_Ptr = _Other_ptr;//赋值原生指针
		}

_Ref_count_base里使 _Weaks +1

	void _Incwref()
		{	// increment weak reference count
		_MT_INCR(_Mtx, _Weaks);
		}

enable_shared_from_this

存在原因

假如有如下几行代码

class A{
public:
    int data;
}
int *pA = NULL;
void main(){
    pA = new A;
    shared_ptr<A> s_p(pA);
}

假设你现在又有想在一个地方,非main作用域里用shared_ptr引用pA,你会怎样做呢,下面这样???

shared_ptr<A> s_p2(pA);

这样是不行滴。有两个shared_ptr分别引用pA,但每个shared_ptr对pA的引用计数都是1,那么当其中一个shared_ptr销毁的时候,会把pA指向的内存释放掉,另一个shared_ptr再引用就不出现不可预知的问题了。

所以应该s_p2在引用原生指针的时候,应该像下面这样。

class A:public enable_shared_from_this<A>
{
public:
    int data;
}
int *pA = NULL;
void main(){
    pA = new A;
    shared_ptr<A> s_p1(pA);
}
//下面是x.cpp文件中
shared_ptr<A> s_p2 = pA->shared_from_this();

不过在给s_p2赋值之前,一定要先有一个s_p1引用pA方可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值