一、需要析構意味着拷貝和賦值
如果自定義析構意味着有指針及其指向的動態內存,採用系統合成的拷貝和賦值將會默認共享動態內存,一旦一個對象離開其作用域,將會致使delete運算符多次釋放同一塊內存。
類使用指針管理內存,如下:
class HasPtr
{
public:
HasPtr(const string &s=string()):ps(new string(s),i(0)){}//參數中分配動態內存
private:
~HasPtr(){delete ps;}//涉及到動態內存必須自定義析構delete這部分內存
string * ps;
int i;
};
ps實現了對new string的管理。如果用戶不自定義拷貝和賦值,編譯器將會默認拷貝指針本身,拷貝不會對動態內存進行拷貝。下面這個例子能夠告知爲什麼需要定義拷貝和賦值:
{
HasPtr a;//構造
HasPtr b=a;//拷貝構造,ok!b對象也有一個指針指向a對象動態內存
HasPtr c;
c=b;//拷貝賦值,ok! c對象也有一個指向a對象動態內存
}
當對象a離開其定義域,調用析構函數進行delete動態內存,成功刪除了!接着輪到對象b析構,再次調用析構函數delete已經析構的a中動態內存,這就有問題了,這部分內容已經不存在了,因此是一個嚴重的設計錯誤;同理c也將會析構一次,同樣是出錯。
二 、需要拷貝也需要賦值
拷貝定義了拷貝應該完成的操作,如序列號+1實現每一個對象都有一個獨一序列號,如果沒有封住賦值是不是實現不了了?沒錯,所以拷貝也要賦值。