智能指針的模擬實現shared_ptr 循環引用 定置刪除器

auto_ptr與scoped_ptr的實現見本人的上篇博客。安全

3、shared_ptride

shared_ptr的實現原理是經過引用計數來實現,只有當引用計數爲1時才釋放空間,不然只需將引用計數減1.拷貝和賦值將引用計數加1,具體代碼以下:函數

template <typename T>
class SharedPtr
{
public:
	SharedPtr();
	SharedPtr(T* ptr);
	SharedPtr(const SharedPtr<T>& ap);
	~SharedPtr();
	//SharedPtr<T>& operator=(const SharedPtr<T>& ptr);//傳統寫法
	SharedPtr<T>& operator=(SharedPtr<T> ap);//現代寫法
	T& operator*()const;
	T* operator->()const;
	long GetCount()const;
	T* GetPtr()const;
protected:
	void _Realease();
protected:
	T* _ptr;
	long* _pCount;
};
template <typename T>
SharedPtr<T>::SharedPtr() :_ptr(NULL), _pCount(new long(1))
{}
template <typename T>
SharedPtr<T>::SharedPtr(T* ptr) : _ptr(ptr), _pCount(new long(1))
{}
template <typename T>
SharedPtr<T>::SharedPtr(const SharedPtr<T>& ap) : _ptr(ap._ptr), _pCount(ap._pCount)
{
	++(*this->_pCount);
}
template <typename T>
SharedPtr<T>::~SharedPtr()
{
	this->_Realease();
}
//template <typename T>//傳統寫法
//SharedPtr<T>& SharedPtr<T>::operator=(const SharedPtr<T>& ap)
//{
//	if (this->_ptr != ap._ptr)
//	{
//		this->_Realease();
//		this->_ptr = ap._ptr;
//		this->_pCount = ap._pCount;
//		++(*this->_pCount);
//	}
//	return *this;
//}
template <typename T>//現代寫法
SharedPtr<T>& SharedPtr<T>::operator=(SharedPtr<T> ap)
{
	swap(this->_ptr, ap._ptr);
	swap(this->_pCount, ap._pCount);
	return *this;
}
template <typename T>
T& SharedPtr<T>::operator*()const
{
	return *(this->_ptr);
}
template <typename T>
T* SharedPtr<T>::operator->()const
{
	return this->_ptr;
}
template <typename T>
long SharedPtr<T>::GetCount()const
{
	return *(this->_pCount);
}
template <typename T>
T* SharedPtr<T>::GetPtr()const
{
	return this->_ptr;
}
template <typename T>
void SharedPtr<T>::_Realease()
{
	if (--(*this->_pCount) == 0)
	{
		delete this->_ptr;
		delete this->_pCount;
	}
}

然而上面用引用計數實現的簡化版看起來不錯,但卻存在如下問題:
this

一、引用計數更新存在着線程安全spa

二、循環引用線程

三、定置刪除器,好比要關閉一個文件,用malloc開闢出來的空間,上述代碼均會出現問題指針

問題1的解決須要對改變引用計數時加鎖。咱們暫時不討論,一下咱們主要看第二個和第三個問題。對象

循環引用:
博客

好比有如下結構體和主函數:it

struct ListNode
{
	shared_ptr<ListNode> _prev; //shared_ptr爲庫文件中實現的,只需包memory便可使用
	shared_ptr<ListNode> _next;
	~ListNode()
	{
		cout << "~ListNode()" << endl;
	}
};
int main()
{
	shared_ptr<ListNode> prev; //語句1
	shared_ptr<ListNode> next; //語句2
	prev->_next = next;        //語句3
	next->_prev = prev;        //語句4
}

經語句一、2以後prev的引用計數爲1,經三、4後爲2,可是最後兩個對象均不能釋放,由於prev的要釋放的前提是next釋放,而next的釋放又依賴於prev的釋放。最後就造成了循環引用,誰都是放不了。解決方案以下:

struct ListNode
{
	weak_ptr<ListNode> _prev;
	weak_ptr<ListNode> _next;
	~ListNode()
	{
		cout << "~ListNode()" << endl;
	}
};

由於weak_ptr(弱引用智能指針)會對引用計數會作特殊處理(上述狀況不加1)。

定置刪除器和空間分配器(ps:空間分配器的定置特殊場景下才會這樣使用)

eg:若是指針是一個指向文件類型的,在析構函數中只需關閉文件便可,而不是釋放空間;若是空間是經過,malloc出來的,那麼在析構函數中要調用free函數,而不是delete操做符。上述問題經過仿函數就能夠解決。具體代碼以下:

template <typename T,class Deleter = Del<T>>
class SharedPtr
{
public:
	SharedPtr(T* ptr);
	SharedPtr(T* ptr, Deleter del);
	SharedPtr(const SharedPtr<T, Deleter>& ap);
	~SharedPtr();
	//SharedPtr<T, Deleter>& operator=(const SharedPtr<T, Deleter>& ptr);//傳統寫法
	//現代寫法
	SharedPtr<T, Deleter>& operator=(SharedPtr<T, Deleter> ap);
	T& operator*()const;
	T* operator->()const;
	long GetCount()const;
	T* GetPtr()const;
protected:
	void _Realease();
protected:
	T* _ptr;
	long* _pCount;
	Deleter _del;
};

template <typename T, class Deleter = Del<T>>
SharedPtr<T, Deleter>::SharedPtr(T* ptr) :_ptr(ptr), _pCount(new long(1))
{}

template <typename T, class Deleter = Del<T>>
SharedPtr<T, Deleter>::SharedPtr(T* ptr, Deleter del) : _ptr(ptr), _pCount(new long(1)), _del(del)
{}

template <typename T, class Deleter = Del<T>>
SharedPtr<T, Deleter>::SharedPtr(const SharedPtr<T, Deleter>& ap) : _ptr(ap._ptr), _pCount(ap._pCount), _del(ap._del)
{
	++(*this->_pCount);
}

template <typename T, class Deleter = Del<T>>
SharedPtr<T, Deleter>::~SharedPtr()
{
	this->_Realease();
}

//template <typename T, class Deleter = Del<T>>//傳統寫法
//SharedPtr<T, Deleter>& SharedPtr<T, Deleter>::operator=(SharedPtr<T, Deleter> ap)
//{
//	if (this->_ptr != ap._ptr)
//	{
//		this->_Realease();
//		this->_ptr = ap._ptr;
//		this->_pCount = ap._pCount;
//		++(*this->_pCount);
//	}
//	return *this;
//}

template <typename T, class Deleter = Del<T>>//現代寫法
SharedPtr<T, Deleter>& SharedPtr<T, Deleter>::operator=(SharedPtr<T, Deleter> ap)
{
	swap(this->_ptr, ap._ptr);
	swap(this->_pCount, ap._pCount);
	swap(this->_del, ap._del);
	return *this;
}

template <typename T, class Deleter = Del<T>>
T& SharedPtr<T, Deleter>::operator*()const
{
	return *(this->_ptr);
}

template <typename T, class Deleter = Del<T>>
T* SharedPtr<T, Deleter>::operator->()const
{
	return this->_ptr;
}

template <typename T, class Deleter = Del<T>>
long SharedPtr<T, Deleter>::GetCount()const
{
	return *(this->_pCount);
}

template <typename T, class Deleter = Del<T>>
T* SharedPtr<T, Deleter>::GetPtr()const
{
	return this->_ptr;
}

template <typename T, class Deleter = Del<T>>
void SharedPtr<T, Deleter>::_Realease()
{
	if (--(*this->_pCount) == 0)
	{
		_del(_ptr);
		delete this->_pCount;
	}
}
相關文章
相關標籤/搜索