1. 程式人生 > 實用技巧 >【C++ primer閱讀記錄】拷貝控制與資源管理

【C++ primer閱讀記錄】拷貝控制與資源管理

拷貝控制

一般來說對於拷貝我們有兩種選擇:使類的行為看起來像一個值或者像一個指標。

類的行為像一個值,意味著它有自己的狀態。當我們拷貝一個像值的物件時,副本和原物件是完全獨立的。

類的物件像指標的話,則為一種共享狀態。當我們拷貝一個這種類的物件時,副本和原物件使用相同的底層資料。改變副本也會改變原物件。

行為像值的類

對於類管理的資源,每個物件都應該都一個自己的拷貝。這需要

定義一個拷貝建構函式,完成string的拷貝,而不是拷貝指標

定義一個解構函式釋放string

定義一個拷貝賦值運算子來釋放當前的string,從右側運算物件拷貝string

編寫拷貝賦值運算子需要記住的:

1)如果將一個值賦予它自身,賦值運算子必須能正確工作。

2)大多數賦值運算子組合了解構函式和拷貝建構函式的工作。

一個好的模式是將右側運算物件拷貝到一個區域性臨時物件中,當拷貝完成後,銷燬左側運算物件的現有成員就是安全的了。一旦左側運算物件的資源被銷燬,就只剩下將資料從臨時物件拷貝到左側運算物件的成員中了。

如果自賦自己值的話,不按照規範來。可能會出現先銷燬左側運算物件,備份右側運算物件的時候發現已經無了。

HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
	auto newp = new string(*rhs.ps); //先對右側賦值引數進行拷貝,newp指向新空間,儲存內容和右側運算										 //值一樣
	delete ps; //刪除左運算值的資料,釋放空間。
	ps = newp; //將newp的地址值交給ps
	return *this;  
	//看起來也可以 ps = new string(*(rhs.ps)) 實際上你需要先釋放掉ps的記憶體空間,如果rhs指向的
    //是自己的話,那就不可以運行了。
}

由於合成解構函式不會使用delete釋放指標,因此如果自己不定義解構函式的話,會導致記憶體洩漏。

如果不定義拷貝建構函式的話,會讓兩個指標指向同一片空間。

行為像指標的類

定義行為類似指標的類,需要為其定義拷貝建構函式和拷貝賦值函式。

但是解構函式不能單方面地釋放關聯的string,只有當最後一個指向string和HasPtr被銷燬時,才可以釋放string。

實際上就需要實現一個類似於shared_ptr來管理類中的資源。我們自己實現的話可以使用引用計數。

為了讓多個物件能夠管理引用技術,解決方法是將計數器儲存在動態記憶體中。當建立一個物件時,我們也分配一個新的計數器(是指直接初始化的建構函式中分配新計數器嗎猜測)。當拷貝或賦值物件時,我們拷貝指向計數器的指標。

練習程式碼:https://github.com/LeeLinSCUT/C-11_Practice