智能指针源码剖析之auto_ptr(VS2019版源码)

一、概念

我们要讨论八种智能指针,分别是:auto_ptr(VC版)、auto_ptr(VS版或Linux版)、scoped_ptr、scoped_array、shared_array、weak_ptr、instrusive_ptr,这篇文章主要详细分析auto_ptr(VS)。

智能指针是在堆上管理内存以及能够自动释放内存的工具,其本质是一个类。在类中分别重载了"=、*、->",目的是模拟指针,让其具有指针的能力。

值得注意的是,在auto_ptr(vs版)中,要着重理解指针指向的内存的拥有权问题(在下文中会详细讲解),其操作十分精妙,以此避免内存泄露的情况发生,但auto_ptr不提倡使用,有很多坑,但作为源码分析足够了。

二、源码剖析

下面是vs2019中auto_ptr智能指针的核心代码:(注释为函数的解释)

template<class _Ty>
	class auto_ptr;

template<class _Ty>
	struct auto_ptr_ref                      //支持将auto_ptr作为临时右值使用
		{	// proxy reference for auto_ptr copying
	explicit auto_ptr_ref(_Ty *_Right)
		: _Ref(_Right)
		{	// construct from generic pointer to auto_ptr ptr
		}

	_Ty *_Ref;	// generic pointer to auto_ptr ptr
	};
template<class _Ty>
	class auto_ptr
	{	// wrap an object pointer to ensure destruction
public:
	typedef _Ty element_type;

	explicit auto_ptr(_Ty * _Ptr = 0) _NOEXCEPT   //构造函数
		: _Myptr(_Ptr)
		{	// construct from object pointer
		}

	auto_ptr(auto_ptr& _Right) _NOEXCEPT  //拷贝构造函数,把原对象指针的指向关掉,并用新对象的指针指向原内存
		: _Myptr(_Right.release())
		{	// construct by assuming pointer from _Right auto_ptr
		}

	auto_ptr(auto_ptr_ref<_Ty> _Right) _NOEXCEPT//拷贝构造,用于接收临时的常类型对象
		{	// construct by assuming pointer from _Right auto_ptr_ref
		_Ty * _Ptr = _Right._Ref;
		_Right._Ref = 0;	// release old
		_Myptr = _Ptr;	// reset this
		}

	template<class _Other>           //这是强制类型转换函数
		operator auto_ptr<_Other>() _NOEXCEPT
		{	// convert to compatible auto_ptr
		return (auto_ptr<_Other>(*this));
		}

	template<class _Other>
		operator auto_ptr_ref<_Other>() _NOEXCEPT //类型转换,使得类的继承关系得以支持
		{	// convert to compatible auto_ptr_ref
		_Other * _Cvtptr = _Myptr;	// test implicit conversion
		auto_ptr_ref<_Other> _Ans(_Cvtptr);
		_Myptr = 0;	// pass ownership to auto_ptr_ref
		return (_Ans);
		}

	template<class _Other> //=重载,看_Other类型的重载函数
		auto_ptr& operator=(auto_ptr<_Other>& _Right) _NOEXCEPT
		{	// assign compatible _Right (assume pointer)
		reset(_Right.release());
		return (*this);
		}

	template<class _Other>
		auto_ptr(auto_ptr<_Other>& _Right) _NOEXCEPT  //拷贝构造
		: _Myptr(_Right.release())
		{	// construct by assuming pointer from _Right
		}

	auto_ptr& operator=(auto_ptr& _Right) _NOEXCEPT  //=重载
		{	// assign compatible _Right (assume pointer)
		reset(_Right.release());
		return (*this);
		}

	auto_ptr& operator=(auto_ptr_ref<_Ty> _Right) _NOEXCEP    //=重载
		{	// assign compatible _Right._Ref (assume pointer)
		_Ty * _Ptr = _Right._Ref;
		_Right._Ref = 0;	// release old
		reset(_Ptr);	// set new
		return (*this);
		}

	~auto_ptr() _NOEXCEPT
		{	// destroy the object
		delete _Myptr;
		}

	_NODISCARD _Ty& operator*() const _NOEXCEPT               //*重载运算符,给指针解引用
		{	// return designated value
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Myptr == 0)
			{
			_DEBUG_ERROR("auto_ptr not dereferencable");
			}
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

		return (*get());
		}

	_NODISCARD _Ty * operator->() const _NOEXCEPT            //->重载运算符,得到指针
		{	// return pointer to class object
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Myptr == 0)
			{
			_DEBUG_ERROR("auto_ptr not dereferencable");    
			}
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

		return (get());
		}

	_NODISCARD _Ty * get() const _NOEXCEPT                   //get函数,得到指针
		{	// return wrapped pointer
		return (_Myptr);
		}

	_Ty * release() _NOEXCEPT         //解除原指针的指向,用临时的指针指向空间,防止内存泄露
		{	// return wrapped pointer and give up ownership
		_Ty * _Tmp = _Myptr;
		_Myptr = 0;
		return (_Tmp);
		}

	void reset(_Ty * _Ptr = 0)        //重新绑定指向的对象,而原来的对象则会被释放。就是我不想指向你了,我想指向其它地方
		{	// destroy designated object and store new pointer
		if (_Ptr != _Myptr)
			delete _Myptr;
		_Myptr = _Ptr;
		}

private:
	_Ty * _Myptr;	// the wrapped object pointer
	};

详细讲解:

①此类中写了一个构造函数,一个析构函数,三个拷贝构造函数,三个赋值重载函数,一个*重载函数,一个->重载函数,一个get函数,一个release函数,一个reset函数,两个类型转换的运算符重载函数(类型转换没有分析透,还请见谅,若有大神能够在评论区讲一讲,感激不尽),各函数的功能已在代码注释中有解释。

②精彩部分讲解:

(1)release函数:在要消除指针指向对象时,我们不能直接让指针赋值为空,因为这样的话,没有指针指向的内存将造成空间泄露,此时就可以声明一个临时指针指向空间,并用返回值返回该指针。

 

③RAII原则,auto_ptr保证的就是RAII对资源的所有权中的变性类型。

RAII概念:RAII,称为“资源获取就是初始化”,是C++等编程语言常用的管理资源、避免内存泄露的方法。它保证在任何情况下,使用对象时先构造对象,最后析构对象。

RAII对资源的所有权的常性类型:指获取资源的地点是构造函数,释放点是析构函数,并且在这两点之间的一段时间里,任何对该RAII类型实例的操纵都不应该从它手里夺走资源的所有权。

RAII对资源的所有权的变性类型:指可以中途被设置为接管另一个资源,或者干脆被置为不拥有任何资源。外部初始化类型是指资源在外部被创建,并被传给RAII实例的构造函数,后者进而接管了其所有权。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值