从源码理解智能指针(二)—— shared_ptr、weak_ptr

目录

计数器

_Ref_count

_Ref_count_del

_Ref_count_del_alloc

_Ptr_base

_Ptr_base的成员变量

构造函数

赋值重载

获取引用计数

减少引用计数

_Reset函数

_Resetw函数

shared_ptr

构造函数

无参构造

用一般参数构造

用完整对象构造

移动构造

析构函数

赋值重载

reset函数

获取资源指针

其他的重载

shared_ptr是否独占资源

循环引用计数问题

weak_ptr

构造函数

赋值重载

析构函数

检查资源是否有效

lock函数

总结


       在前面一文中,分析了auto_ptr和unique_ptr两种智能指针,二者都是独占式指针,即资源只能由一个智能指针拥有并管理。本文就来分析一下另外两种非独占式智能指针——共享式指针shared_ptrweak_ptr

       共享式指针允许多个智能指针持有同一资源,并且当没有智能指针持有该资源时就自动销毁资源。为了实现共享+智能,就需要用到一个计数器,来记录某个资源被多少对象持有,当计数值为0时,就销毁该资源。

       在shared_ptr和weak_ptr中,这样的计数器实际上是一个单独的类。它主要负责资源引用计数(增加、减少)以及资源的释放。此外,通过计数器,还能像unique_ptr那样指定删除器,还增加了一个空间分配器。下面就先来分析一下计数器:

计数器

       计数器的根本,是一个抽象类_Ref_count_base,其定义如下:

class _Ref_count_base       //管理计数变量        虚基类
	{	// common code for reference counting
private:
	virtual void _Destroy() = 0;
	virtual void _Delete_this() = 0;

private:
	_Atomic_counter_t _Uses;    //引用计数
	_Atomic_counter_t _Weaks;   //弱引用计数

protected:
	_Ref_count_base()   //初始化两个计数变量为1
		{	// construct
		_Init_atomic_counter(_Uses, 1);
		_Init_atomic_counter(_Weaks, 1);
		}

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

	......

	unsigned int _Get_uses() const  //返回引用计数
		{	// return use count
		return (_Get_atomic_count(_Uses));
		}

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

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

	void _Decref()
		{	// decrement use count
		if (_MT_DECR(_Mtx, _Uses) == 0)
			{	// destroy managed resource, decrement weak reference count
			_Destroy();
			_Decwref();  //如果资源已经被释放了,那么weak_ptr也没有任何作用了,
			}
		}

	void _Decwref()
		{	// decrement weak reference count
		if (_MT_DECR(_Mtx, _Weaks) == 0) //如果_Weaks-1后为0,就调用_Delete_this
			_Delete_this();  //释放当前对象
		}

	long _Use_count() const  //返回引用计数
		{	// return use count
		return (_Get_uses());
		}

	bool _Expired() const  //检测是否失效,失效是指引用计数为0
		{	// return true if _Uses == 0
		return (_Get_uses() == 0);
		}

	virtual void *_Get_deleter(const _XSTD2 type_info&) const
		{	// return address of deleter object
		return (0);
		}
	};

_Ref_count_base中主要包含以下信息:

1.两个纯虚函数_Destroy()和_Delete_this(),意味着二者必须在子类中实现,前者用来释放计数器对应的资源,后者用来释放计数器自身

2.两个计数变量_Uses和_Weaks,前者是强引用计数,主要用于shared_ptr中,后者用于weak_ptr中;

3.定义了对_Uses和_Weaks的增加、减少函数。如果某一次减少使得_Uses为0,那么就会调用子类中实现的_Destroy函数并且减少_Weaks;如果某一次减少使得_Weaks为0,就会调用子类中实现的_Delete_this函数;

4._Ref_count_base的构造会初始化_Uses和_Weaks为1;

5._Uses和_Weaks的增加、减少都是原子操作

     显然,作为一个抽象类,不可能仅仅通过_Ref_count_base来实现计数器的,真正的计数器是子类来实现,_Ref_count_base的子类有三种:_Ref_count、_Ref_count_del和_Ref_count_del_alloc。从子类名也可以看出来,从前往后三种子类的功能更强大,体现在计数、删除器和分配器三个方面。

_Ref_count

     _Ref_count就是一种计数器,它内部的成员变量只含一个资源指针_Ptr,其定义如下:

template<class _Ty>
	class _Ref_count     
	: public _Ref_count_base  //父类中管理计数变量,_Ref_count中管理其相应的资源
	{	// handle reference counting for object without deleter
public:
	_Ref_count(_Ty *_Px)
		: _Ref_count_base(), _Ptr(_Px)
		{	// construct
		}

private:
	virtual void _Destroy()  //重写虚基类中的_Destroy
		{	// destroy managed resource
		delete _Ptr;   //释放资源
		}

	virtual void _Delete_this()
		{	// destroy self
		delete this;  //销毁当前对象
		}

	_Ty * _Ptr;   //资源指针
	};

该类中主要包含以下信息:

1._Ref_count中含有一个资源指针_Ptr,指向该计数器对应的资源;

2._Ref_count从_Ref_count_base_继承来的计数变量相关操作,都是针对_Ptr的;

3._Ref_count类中必须重写_Destroy和_Delete_this函数,前者对_Ptr进行释放,后者用来析构当前计数器对象。由于_Ref_count_base_的析构函数是虚函数,因此_Ref_count可以完全析构;

4._Ref_count类只接受用资源指针构造

_Ref_count_del

     _Ref_count_del是第二种计数器,它除了拥有资源指针外,还拥有一个删除器实例,如下所示:

template<class _Ty,
	class _Dx>
	class _Ref_count_del
	: public _Ref_count_base //父类中管理计数变量,_Ref_count_del中管理相应的资源指针和删除器
	{	// handle reference counting for object with deleter
public:
	_Ref_count_del(_Ty *_Px, _Dx _Dt)
		: _Ref_count_base(), _Ptr(_Px), _Dtor(_Dt)
		{	// construct
		}

	virtual void *_Get_deleter(const _XSTD2 type_info& _Typeid) const
		{	// return address of deleter object
		return ((void *)(_Typeid == typeid(_Dx) ? &_Dtor : 0));
		}

private:
	virtual void _Destroy()
		{	// destroy managed resource
		_Dtor(_Ptr);
		}

	virtual void _Delete_this()
		{	// destroy self
		delete this;
		}
	//资源指针以及删除器
	_Ty * _Ptr;
	_Dx _Dtor;	// the stored destructor for the controlled object
	};

该类主要包含以下信息:

1._Ref_count_del除了有一个资源指针_Ptr,还有一个_Dx类型的删除器实例_Dtor;

2._Ref_count_del从_Ref_count_base_继承来的计数变量相关操作,都是针对_Ptr的;

3.重写的_Destroy函数中,并不像_Ref_count那样直接调用delete删除,而是使用的_Dtor(_Ptr),这说明删除器必须是一个仿函数类,_Delete_this和上述相同;

4._Ref_count_del只接受用资源指针和删除器实例来构造。

_Ref_count_del_alloc

       最后一种计数器,除了包含一个删除器实例,还包含一个分配器实例,如下所示:

template<class _Ty,
	class _Dx,
	class _Alloc>
	class _Ref_count_del_alloc
	: public _Ref_count_base //父类中管理计数变量,_Ref_count_del_alloc中管理相应的资源指针、删除器和分配器
	{	// handle reference counting for object with deleter and allocator
public:
	typedef _Ref_count_del_alloc<_Ty, _Dx, _Alloc> _Myty;
	typedef typename _Alloc::template rebind<_Myty>::other _Myalty;

	_Ref_count_del_alloc(_Ty *_Px, _Dx _Dt, _Myalty _Al)
		: _Ref_count_base(), _Ptr(_Px), _Dtor(_Dt), _Myal(_Al)
		{	// construct
		}

	virtual void *_Get_deleter(const _XSTD2 type_info& _Typeid) const
		{	// return address of deleter object
		return ((void *)(_Typeid == typeid(_Dx) ? &_Dtor : 0));//如果传入的类型与删除器类型相同,就返回删除器地址
		}

private:
	virtual void _Destroy()
		{	// destroy managed resource
		_Dtor(_Ptr);   //将资源指针作为参数调用删除器
		}

	virtual void _Delete_this()
		{	// destroy self
		_Myalty _Al = _Myal; 
		_Al.destroy(this);
		_Al.deallocate(this, 1);
		}
	//资源指针、删除器、分配器
	_Ty * _Ptr;
	_Dx _Dtor;	// the stored destructor for the controlled object
	_Myalty _Myal;	// the stored allocator for this
	}

该类主要包含以下信息:

1._Ref_count_del_alloc增加了一个分配器实例;

2._Ref_count_del_alloc从_Ref_count_base_继承来的计数变量相关操作,都是针对_Ptr的;

3.重写的_Destroy函数中,用仿函数类实例_Dtor来销毁资源指针,而在重写的_Delete_this中,则是通过分配器实例来进行的,可见,分配器中必须实现destroy函数和deallocate函数(这就很像STL中的allocator);

4._Ref_count_del只接受用资源指针、删除器实例和分配器实例来构造。

 

      可以看到,计数器实际上是通过_Ref_count_base的三个子类来实现的,这三种子类中都包含了一个资源指针,调用的destroy函数也是用来删除资源指针所指向的“资源”,可以理解为,计数器实际上就已经绑定到了某一处资源上。从这一点上,我们也大致能猜出,shared_ptr和weak_ptr之所以能和计数器对应起来,就是靠同一处资源。

_Ptr_base

       在分析shared_ptr和weak_ptr之前,需要先分析另一个很重要的类——_Ptr_base。shared_ptr和weak_ptr都继承自它,现在来看看这个类的定义。

_Ptr_base的成员变量


                
  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值