智能指針的模擬實現 auto_ptr scoped_ptr shared_ptr

RAII(Resource Acquisition Is Initialization)

資源分配即初始化,定義一個類來封裝資源的分配和釋放,在構造函數完成資源的分配和初始化,在析構函數完成資源的清理,可以保證資源的正確初始化和釋放。

智能指針:用自動化或者說智能的指針來實現對動態內存的釋放。它是一個類,有類似指針的功能。

常見的智能指針:auto_ptr/scoped_ptr/scoped_array/shared_ptr/shared_array,由於scoped_array和scoped_ptr比較類似,shared_array和shared_ptr又比較類似,所以我們只實現auto_ptr/scoped_ptr/shared_ptr。

一、auto_ptr

最開始auto_ptr的成員變量主要有T* _ptr,bool _owner,主要實現原理是在構造對象時賦予其管理空間的所有權,在析構函數中通過_owner的真否來釋放所有權,並且在拷貝或賦值後通過將_owner設爲false,轉移空間的所有權。具體實現代碼如下:

template <typename T>
class AutoPtr
{
public:
	AutoPtr(T* ptr = NULL);
	AutoPtr(AutoPtr<T>& ap);
	AutoPtr<T>& operator=(AutoPtr<T>& ap);
	~AutoPtr();
	T& operator*()const;
	T* operator->()const;
	T* GetStr()const;
protected:
	T* _ptr;
	bool _owner;
};

template <typename T>
AutoPtr<T>::AutoPtr(T* ptr) : _ptr(ptr), _owner(true)
{}

template <typename T>
AutoPtr<T>::AutoPtr(AutoPtr<T>& ap) : _ptr(ap._ptr), _owner(true)
{
	ap._owner = false;
}

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

template <typename T>
AutoPtr<T>::~AutoPtr()
{
	if (this->_ptr)
	{
		this->_owner = false;
		delete this->_ptr;
	}
}

template <typename T>
T& AutoPtr<T>::operator*()const
{
	return *(this->_ptr);
}

template <typename T>
T* AutoPtr<T>::operator->()const
{
	return this->_ptr;
}

template <typename T>
T* AutoPtr<T>::GetStr()const
{
	return (this->_ptr);
}

主要問題:如果拷貝出來的對象比原來的對象出作用域,則原來的對象的_owner雖然爲false,但卻課訪問一塊已經釋放的一塊空間。

auto_ptr的第二種實現方法:還是管理空間的所有權轉移,但這種實現方法中沒有_owner。構造和析構和上述實現方法類似,但拷貝和賦值後直接將_ptr賦爲空,禁止其在訪問原來的內存空間。具體代碼如下:

template <typename T>
class AutoPtr
{
public:
	AutoPtr();
	AutoPtr(T* ptr);
	AutoPtr(AutoPtr<T>& ap);
	AutoPtr<T>& operator=(AutoPtr<T>& ap);
	~AutoPtr();
	T& operator*()const; 
	T* operator->()const;
	T* GetStr()const;
protected:
	T* _ptr;
};

template <typename T>
AutoPtr<T>::AutoPtr() : _ptr(NULL)
{}

template <typename T>
AutoPtr<T>::AutoPtr(T* ptr) : _ptr(ptr)//不能寫成const T* ptr,因爲否則爲const類型的賦值給非const類型
{}

template <typename T>
AutoPtr<T>::AutoPtr(AutoPtr<T>& ap) : _ptr(ap._ptr)
{
	ap._ptr = NULL;
}

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

template <typename T>
AutoPtr<T>::~AutoPtr()
{
	if (this->_ptr)
	{
		delete this->_ptr;
	}
}

template <typename T>
T& AutoPtr<T>::operator*()const
{
	return *(this->_ptr);
}

template <typename T>
T* AutoPtr<T>::operator->()const
{
	return this->_ptr;
}

template <typename T>
T* AutoPtr<T>::GetStr()const
{
	return (this->_ptr);
}

二、scoped_ptr

scoped_ptr的實現原理是防止對象的拷貝與賦值。具體實現是將拷貝構造函數和賦值運算符重載函數設置爲保護或私有,並且只聲明不實現,設置爲保護或私有是防止他人在類外自己實現。具體代碼如下:

template <typename T>
class ScopedPtr
{
public:
	ScopedPtr(T* ptr = NULL);
	~ScopedPtr();
	T* operator->()const;
	T& operator*()const;
	T* GetPtr()const;
protected:
	ScopedPtr(const ScopedPtr<T>& ptr);
	ScopedPtr<T>& operator=(const ScopedPtr<T>& ptr);
protected:
	T* _ptr;
};

template <typename T>
ScopedPtr<T>::ScopedPtr(T* ptr) :_ptr(ptr)
{}

template <typename T>
ScopedPtr<T>::~ScopedPtr()
{
	if (this->_ptr)
	{
		delete this->_ptr;
	}
}

template <typename T>//應用於類型爲結構體時
T* ScopedPtr<T>::operator->()const
{
	return this->_ptr;
}

template <typename T>
T& ScopedPtr<T>::operator*()const
{
	return *(this->_ptr);
}

template <typename T>
T* ScopedPtr<T>::GetPtr()const
{
	return (this->_ptr);
}

shared_ptr的實現及相關問題見下篇博客。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章