C++ auto_ptr的簡單模擬實現

一、auto_ptr的簡單模擬實現

關於auto_ptr的缺陷我在之前的博客中就已經說明。在這篇博客中我們從它的底層來更進一步闡述。

在學習中,對某一個類進行簡單的模擬,一般情況下,我們只需要模擬實現四個函數,分別是:構造函數、析構函數、拷貝構造函數以及賦值運算符重載。但是對於一個指針來說,它還要加上*運算符重載->運算符重載

	template<class T>
	class Auto_ptr
	{
	public:

		//構造函數
		Auto_ptr(T* _ptr=NULL)
		{
			ptr = _ptr;
		}

		//析構函數
		~Auto_ptr()
		{
			if (ptr != NULL)
			{
				delete ptr;
			}
		}

		//拷貝構造函數
		Auto_ptr(const Auto_ptr<T>& ap)
		{
			ptr = ap.ptr;
			ap.ptr = NULL;
		}

		//賦值運算符重載
		Auto_ptr<T>& operator=(Auto_ptr<T>& ap)
		{
			if (this != &ap)
			{
				if (ptr != NULL)
					delete ptr;

				ptr = ap.ptr;
				ap.ptr = NULL;

			}

			return *this;
		}

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

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

	private:
		T * ptr;
	};

二、對auto_ptr的缺陷的分析

從賦值運算符重載函數和拷貝構造函數來看,他們所使用的的是一個淺拷貝,所以如果auto_ptr對象之間出現了賦值和拷貝的情況,那麼就會出現,多個指針指向了同一個空間的情況,在對象聲明週期結束的時候,會出現同一塊空間被多次釋放的情況,所以爲了改變這種情況,auto_ptr使用的是一個管理權轉移的思想,所以在發生拷貝構造或者是賦值時,將原來的auto_ptr置爲空,這樣就解決了二次釋放的問題。但是這樣也有一個缺陷,那就是在用原來的auto_ptr訪問數據時,會出現內存錯誤,因爲此時的auto_ptr是一個NULL,用一個NULL去訪問數據顯然是C++不允許的。

三、對賦值運算符重載函數的一些說明

(1)賦值運算符重載
對於一個賦值運算符重載,我們有以下四點要注意的地方(注意這不僅僅是對於以上代碼而言,對於所有的賦值運算符重載都適用):

  1. 檢查返回值類型是否是該類類型的引用,並且返回值也是自身引用(即*this)。
    因爲只有返回一個引用類型,那麼才能做到連續賦值(即s1=s2=s3),否則如果函數返回的不是一個引用,那麼在進行連續賦值的時候,編譯器就會報錯。

  2. 檢查函數的形參是否是const引用類型。
    因爲如果傳入的參數不是引用,而是一個實例的話,那麼在實參對形參結合的這個過程中會調用拷貝構造函數。而如果是一個引用就會避免這種無端的銷燬,從而提高效率。之所以聲明爲const,是因爲在賦值運算符中,我們可以保證不會對對象進行修改。

  3. 檢查在賦值之前是否釋放掉自身已有內存
    如果我們忘記在賦值之前釋放掉自身已有內存,那麼就會出現內存泄漏。

  4. 檢查是否判斷自我賦值

    因爲在賦值運算符重載函數中,我們首先要對自身對象進行釋放,然後纔開始賦值。如果沒有判斷自我賦值,那麼當是同一個對象進行賦值時,釋放掉自身對象,其實也是將傳入參數的內存也釋放掉了,因此就找不到要賦值的內容了。

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