一般編譯器會自定義預設的拷貝建構函式,但是當類中含有指標成員時,常常需要我們自己定義拷貝建構函式。
基本原則:1、當我們需要自定義析構函式時,通常也需要自定義拷貝建構函式。
2、需要拷貝建構函式時通常也需要自定義拷貝賦值運算子,反之亦然。
有兩種拷貝方式,深拷貝和淺拷貝。
當我們自定義的類中有指標型別的資料成員時,深拷貝會更加安全。所謂深拷貝就是開闢一塊新的記憶體空間,將另乙個物件的成員逐一拷貝到新的記憶體空間。
下面考慮自己實現乙個string類,主要是自己實現建構函式、析構函式、拷貝建構函式、拷貝賦值運算子。
1、形參為const引用型別,防止改變傳入的實參。class
mystring
;//建構函式
mystring::
mystring
(const
char
* str)
else
}//析構函式
mystring::
~mystring()
//拷貝建構函式
mystring::
mystring
(const mystring& other)
//傳參為const& 加分點
//過載賦值運算子
//1、返回型別為類的引用型別,返回*this
//2、傳入引數必須為const 引用型別
//3、釋放原來指標的記憶體
//4、刪除原來的指標之前必須要判斷引數與this是不是指向同乙個位址,是則返回*this
mystring& mystring::
operator=(
const mystring& other)
2、實現深拷貝,先釋放原來的記憶體,再申請新的記憶體空間,將拷貝物件的字串拷貝到新記憶體空間中。
如果是淺拷貝,當兩個string類指向同一塊位址空間時,乙個string呼叫了析構,釋放了記憶體空間,此時另乙個string所指向的位址是沒有意義的,如果這時候呼叫string訪問這塊已經**的記憶體將產生未知行為。
深拷貝就不會有這樣的問題,因為重新申請了新的記憶體,但是深拷貝效率上會很慢。
返回型別為引用型別,返回*this(如果返回值型別,將呼叫拷貝建構函式)
形參為const 引用型別;(const 說明不改變=右側的值,引用傳參不會呼叫拷貝)
要考慮自賦值的操作,即判同測試,因為賦值之前要釋放『=』左側變數的記憶體空間,避免把自身的記憶體給釋放掉;
避免記憶體洩漏,當不是自賦值時,先釋放掉原來的內記憶體空間。
當我們需要實現類似智慧型指標shared_ptr時,拷貝的操作常常會是淺拷貝,只需要拷貝指標本身,拷貝之後的指標指向同一塊記憶體,不需要申請新的記憶體空間,但是同時需要維護乙個引用計數記錄該記憶體被共享的次數。
引用計數需要用指標實現,因為多個變數共用同乙個引用計數,儲存在堆記憶體中。
考慮實現乙個簡單的智慧型指標:
初始化引用計數指標,初始值為1;class
hasptr
~hasptr()
}//拷貝建構函式,ps指向同乙個記憶體,共享同乙個引用計數
hasptr
(const hasptr& rhs)
hasptr&
operator=(
const hasptr& rhs)
ps = rhs.ps;
//淺拷貝
use = rhs.use;
++* use;
return
*this;}
private
: string* ps;
// size_t* use;
//引用計數
};
初始化指標成員;
每次呼叫析構函式將引用值減一,當引用值為0時銷魂物件釋放記憶體空間
指標成員直接賦指標值,不需要深拷貝
引用計數指標變數值也是直接賦值,引用計數加1
形參依然為const &型別
1、返回型別為&,返回*this,形參為const &;
2、首先處理自賦值,先經行判同測試;
3、「=」 左側變數引用計數值減一,判斷若引用計數值為0 則呼叫delete釋放記憶體;
4、指標成員直接賦值,不需要申請新記憶體;
5、右側變數引用計數值加一;
拷貝建構函式和賦值運算子
把引數傳遞給函式有三種方法,一種是值傳遞,一種是傳位址,還有一種是傳引用。前者與後兩者不同的地方在於 當使用值傳遞的時候,會在函式裡面生成傳遞引數的乙個副本,這個副本的內容是按位從原始引數那裡複製過來的,兩者的內容是相同的。當原始引數是乙個類的物件時,它也會產生乙個物件的副本,不過在這裡要注意。一般...
拷貝建構函式與賦值運算子
物件的 生命週期 管理意味著完全地控制物件的誕生 繁殖和消亡的過程。使用拷貝建構函式和賦值運算子,可以更快的進行物件的繁殖操作。拷貝建構函式是一種建構函式,其原型類似於 classname const classname x 賦值建構函式的作用就是建立乙個物件,該物件是同乙個類中已有物件的精確副本。...
拷貝建構函式和賦值運算子
來自 本文主要介紹了拷貝建構函式和賦值運算子的區別,以及在什麼時候呼叫拷貝建構函式 什麼情況下呼叫賦值運算子。最後,簡單的分析了下深拷貝和淺拷貝的問題。在預設情況下 使用者沒有定義,但是也沒有顯式的刪除 編譯器會自動的隱式生成乙個拷貝建構函式和賦值運算子。但使用者可以使用delete來指定不生成拷貝...