假設有一個如下的MyClass類:
class MyClass
{
public:
//構造函數
//拷貝構造函數
MyClass(const MyClass& that)
: int_data_(that.int_data_),
dbl_data_(that.dbl_data_),
str_data_(that.str_data_)
{
}
//賦值操作符
MyClass& operator = (const MyClass& that)
{
if(this != that)
{
int_data_ = that.int_data_;
dbl_data_ = that.dbl_data_;
str_data_ = that.str_data_;
}
return *this;
}
//一些其他方法
private:
Int int_data_;
Double dbl_data_;
string str_data_;
//每次在這裏添加一個新的數據成員時,不要忘了在拷貝構造函數和賦值操作中添加對應的代碼
};
對於這個類,存在什麼問題呢?真正的問題是,在私有部分後面的註釋指出了問題的所在。如果像註釋中所說的,這樣的操作特別麻煩而且極易犯錯誤。事實上,如果我們沒有編寫拷貝構造函數和賦值操作符,C++會爲我們編寫一個“默認版本”。
拷貝構造函數的默認版本爲所有的數據成員調用拷貝構造函數(或簡單的複製內置類型),賦值操作符的默認版本將調用每個數據成員的賦值操作符或者簡單的複製內置類型。
因此,對於上面的例子,拷貝構造函數和賦值操作符完全不是必需的。更糟的是,它們是潛在的錯誤之源,因爲它們使代碼變得脆弱。如果有人試圖改變它們,就可能對代碼產生破壞。
因此,對於上述的例子,比較好的思路是徹底避免編寫拷貝構造函數和賦值操作符。
一般而言,有幾種方式可供選擇:
- 依賴編譯器自動創建的默認版本
- 把拷貝構造函數和賦值操作符聲明爲私有,並且不提供實現,禁止任何類型的複製
- 編寫自己的版本
總結:
- 只要有可能,避免編寫拷貝構造函數和賦值操作符
- 如果默認版本並不適用,可以考慮把拷貝構造函數和賦值操作符聲明爲私有,禁止類實例的複製