c++中的new
和delete
關鍵字給了使用者更大的自由對記憶體進行管理,但是如果使用不當就很容易造成記憶體洩漏。在建立和使用類的時候,需要額外小心,因為對類的建立和銷毀行為的管理不當是造成記憶體洩漏的重要原因。下面是乙個反面教材:
class badstring;
badstring::badstring()
badstring::badstring(const char * s)
badstring::~badstring()
void badstring::show()
void badstring::shownum()
int badstring::num = 0; //必須要在主函式之外初始化
badstring s;
s.shownum(); //輸出字串的個數為1
badstring tem = s; //初始化,出錯的地方
tem.shownum(); //輸出字串的個數還是為1
上述程式可能可以通過編譯,但是在執行的時候會報錯,報錯的原因是重複釋放已經釋放的空間
,其出錯的原因就是在badstring tem1 = s1;
這一行**。並且這行**還會導致另乙個錯誤,明明程式建立了s
和tem
兩個物件,但是類中靜態變數num
記錄到的物件個數還是1。
乙個錯誤是num
值不一致的問題。這個錯誤出現是因為初始化tem
的時候,沒有呼叫事先定義好的建構函式,而是呼叫了複製建構函式
,而預設的複製建構函式中沒有對num
加一。複製建構函式是每當程式產生物件副本時呼叫的建構函式
,其函式簽名如下所示:
classname(const classname &);
所以上面badstring tem = s
的執行效果實際上是這樣:
badstring tem = badstring(s);
另乙個錯誤是對堆記憶體重複釋放的問題。這行**為tem1
在棧中建立了乙個記憶體空間,並且將物件s
中的每乙個成員的值複製給tem
。這個複製是淺複製
,只是單純複製成員的變數,而s.str
是乙個指標,指向的是堆記憶體中的一塊記憶體,這就導致了s.str
和tem.str
同時指向一塊記憶體。當程式執行完畢,系統摧毀兩個變數的時候就會對同一塊記憶體釋放兩次,從而造成執行錯誤。要想解決這個問題,只需要在自己實現的複製建構函式中重新分配記憶體,並把s.str
的值複製進去即可,記得在類宣告中加入複製建構函式的宣告
:
badstring::badstring(const badstring & s)
加入這樣的複製建構函式的定義之後,上述的兩個錯誤都將解決。
上述的複製建構函式只是在物件初始化的時候才會呼叫,而對於賦值操作,編譯器不會呼叫複製建構函式。例如:
badstring s;
s.shownum();
badstring tem;
tem = s; //賦值操作,不會呼叫複製建構函式
tem.shownum();
預設的賦值運算子=
的操作跟預設的複製建構函式一樣,只是淺複製
,所以要對=
過載來實現深複製
,來解決這個問題,過載=
的函式形式為:
classname & operator=(const classname &);
在使用的時候(例如tem = s
),=
左邊是呼叫物件,該函式的呼叫物件是左邊的物件,所以函式直接可以訪問物件中的私有成員,以修改其值。返回引用的原因是實現連續賦值。
下面是乙個對badstring
類過載=
的例子:
badstring & badstring::operator=(const badstring & s)
複製建構函式
今天回看了前面的內容,發現這一章掌握的不夠好,就重看了一遍,順便總結一下 無規律總結 複製建構函式用於複製物件,即可以初始化物件,也可以將複製得到的物件作為實參傳遞給函式,多用於初始化。當我們這樣寫 string null bulk 9 9 9 9 在建立null bulk時編譯器先呼叫string...
複製建構函式
拷貝建構函式的標準寫法如下 class base base const base b 上述寫法見得最多,甚至你認為理所當然。那麼如果我們不寫成引用傳遞呢,而是值傳遞,那麼會怎樣?class base base const base b 編譯出錯 error c2652 base illegal co...
複製建構函式
呼叫複製建構函式的情形 在c 中,下面三種物件需要呼叫複製建構函式 1 乙個物件作為函式引數,以值傳遞的方式傳入函式體 2 乙個物件作為函式返回值,以值傳遞的方式從函式返回 3 乙個物件用於給另外乙個物件進行初始化 常稱為賦值初始化 4 編譯器生成臨時物件 一 乙個物件作為函式引數,以值傳遞的方式傳...