C++智能指针深度理解

1、auto_ptr (不要使用的指针)

没有智能指针的c++时代,对堆内存的管理就是简单的new delete。
但是缺点是容易忘了delete释放,即使是资深码农,也可能会在某一个地方忘记delete它,造成内存泄漏。在实际工程中,我们往往更希望把精力放在应用层上,而不是费尽心思在语言的细枝末节(内存的释放)。
于是就有了这个最原始的智能指针。

auto_ptr源码:

template<typename T>
class AutoPtr
{
public:
	explicit AutoPtr(T * ptr = NULL):_ptr(ptr), _owner(true)
	{}
	
	AutoPtr(AutoPtr<T>& ap) 
		:_ptr(ap._ptr), _owner(true)		
	{
		ap._owner = false;  
	}
	AutoPtr& operator=(AutoPtr<T>& ap)
	{
		if (this != &ap)
		{
			delete this->_ptr;
			this->_ptr = ap._ptr;
			
			this->_owner = true;
			ap._owner = false;
		}
		return *this;
	}
	~AutoPtr()
	{
		if (_owner)
		{
			this->_owner = false;
			delete this->_ptr;
		}
	}

	T& operator*()
	{
		return *(this->_ptr);
	}

	T* operator->()
	{
		return this->_ptr;
	}
	T* GetStr()
	{
		return (this->_ptr);
	}
protected:
	T * _ptr;
	bool _owner; 
};

auto_ptr 的升级:

template<typename T>
class AutoPtr
{
public:	explicit AutoPtr(T* ptr = NULL)
		:_ptr(ptr)
	{}
	AutoPtr(AutoPtr<T>& ap)
		:_ptr(ap._ptr)
	{
		ap._ptr = NULL;
	}
	AutoPtr& operator=(AutoPtr<T>& ap)
	{
		if (this != &ap)
		{
			delete this->_ptr;
			this->_ptr = ap._ptr;
			ap._ptr = NULL;
		}
		return *this;
	}
	~AutoPtr()
	{
		if (_ptr)
		{
			delete _ptr;
		}
	}

	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}
	T* GetStr()
	{
		return _ptr;
	}
protected:
	T* _ptr;
};

2、unique_ptr (一种强引用指针)

它是我的所有物,你们都不能碰它!”——鲁迅
正如它的名字,独占 是它最大的特点。

它其实算是auto_ptr的翻版(都是独占资源的指针,内部实现也基本差不多).
但是unique_ptr的名字能更好的体现它的语义,而且在语法上比auto_ptr更安全(尝试复制unique_ptr时会编译期出错,而auto_ptr能通过编译期从而在运行期埋下出错的隐患)
假如你真的需要转移所有权(独占权),那么你就需要用std::move(std::unique_ptr对象)语法,尽管转移所有权后
还是有可能出现原有指针调用(调用就崩溃)的情况。 但是这个语法能强调你是在转移所有权,让你清晰的知道自己在做什么,从而不乱调用原有指针。

unique_ptr 源码:

template<typename T>
class  quiquePtr
{
public:
	quiquePtr(T* ptr = NULL)
		:_ptr(ptr)
	{}
	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}

	T* GetStr()
	{
		return _ptr;
	}
	//析构函数
	~quiquePtr()
	{
		if (_ptr != NULL)
		{
			delete _ptr;
		}
	}
protected:
	//防拷贝
	quiquePtr(quiquePtr<T>& ap);
	quiquePtr& operator=(quiquePtr<T>& ap);

	T* _ptr;
};

3、shared_ptr(一种强引用指针)

“它是我们(shared_ptr)的,也是你们(weak_ptr)的,但实质还是我们的”
——鲁迅

共享对象所有权是件快乐的事情。多个shared_ptr指向同一处资源,当所有shared_ptr都全部释放时,该处资源才释放。(有某个对象的所有权(访问权,生命控制权)
即是 强引用,所以shared_ptr是一种强引用型指针)

每个shared_ptr都占指针的两倍空间,一个装着原始指针,一个装着计数区域(SharedPtrControlBlock)的指针(用原始指针构造时,会new一个SharedPtrControlBlock出来作为计数存放的地方,然后用指针指向它,计数加减都通过SharedPtrControlBlock指针间接操作。)

SharedPtr源码:

template<typename T>
class SharedPtr
{
public:
	SharedPtr(T* ptr = NULL):_ptr(ptr), _refCount(new long(1))
	{
	}
	~SharedPtr()
	{
		_Release();
	}
	SharedPtr(const SharedPtr<T> & sp):_ptr(sp._ptr), _refCount(sp._refCount)
	{
		++(*_refCount);
	}
	//传统写法
	SharedPtr<T>& operator=(const SharedPtr<T>& sp)
	{
		if (this != &sp)
		{
			this->_Release();
			_refCount = sp._refCount;
			_ptr = sp._ptr;
			++(*_refCount);
		}
		return *this;
	}
	//现代写法
	/*SharedPtr<T> & operator=(SharedPtr<T> sp)
	{
		swap(_ptr, sp._ptr);
		swap(_refCount, sp._refCount);
		++(*_refCount);
		return *this;
	}*/
	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}
	T* GetPtr()
	{
		return _ptr;
	}
	long GetCount()
	{
		return *_refCount;
	}
protected:
	void _Release()
	{
		if (--(*_refCount) == 0)
		{
			//delete _ptr;
			delete(_ptr);
			delete _refCount;
		}
	}
protected:
	T * _ptr;
	long * _refCount;    //引用计数
	template<typename T>
	friend class WeakPtr;
};

4、weak_ptr(一种弱引用指针)

它是我们(weak_ptr)的,也是你们(shared_ptr)的,但实质还是你们的”
——鲁迅

weak_ptr是为了辅助shared_ptr的存在,它只提供了对管理对象的一个访问手段,同时也可以实时动态地知道指向的对象是否存活。
(只有某个对象的访问权,而没有它的生命控制权 即是 弱引用,所以weak_ptr是一种弱引用型指针)

内部大概实现:
计数区域(SharedPtrControlBlock)结构体引进新的int变量weak_count,来作为弱引用计数。
每个weak_ptr都占指针的两倍空间,一个装着原始指针,一个装着计数区域的指针(和shared_ptr一样的成员)。
weak_ptr可以由一个shared_ptr或者另一个weak_ptr构造。
weak_ptr的构造和析构不会引起shared_count的增加或减少,只会引起weak_count的增加或减少。
被管理资源的释放只取决于shared计数,当shared计数为0,才会释放被管理资源, 也就是说weak_ptr不控制资源的生命周期。
但是计数区域的释放却取决于shared计数和weak计数,当两者均为0时,才会释放计数区域。

WeakPtr源码:

template<typename T>
class WeakPtr
{
public:
	WeakPtr(T* ptr = NULL) :_ptr(ptr)
	{
	}
	~WeakPtr()
	{
	}
	WeakPtr(const WeakPtr<T>& sp) :_ptr(sp._ptr)
	{
	}
	WeakPtr(const SharedPtr<T>& sp) :_ptr(sp._ptr)
	{
	}
	//传统写法
	WeakPtr<T>& operator=(const SharedPtr<T>& sp)
	{
		_ptr = sp._ptr;
		return *this;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
protected:
	T* _ptr;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值