【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來管理類中的資源。我們自己實現的話可以使用引用計數。
為了讓多個物件能夠管理引用技術,解決方法是將計數器儲存在動態記憶體中。當建立一個物件時,我們也分配一個新的計數器(是指直接初始化的建構函式中分配新計數器嗎猜測)。當拷貝或賦值物件時,我們拷貝指向計數器的指標。