拷貝構造函數和賦值操作符

假設有一個如下的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++會爲我們編寫一個“默認版本”。

拷貝構造函數的默認版本爲所有的數據成員調用拷貝構造函數(或簡單的複製內置類型),賦值操作符的默認版本將調用每個數據成員的賦值操作符或者簡單的複製內置類型。

因此,對於上面的例子,拷貝構造函數和賦值操作符完全不是必需的。更糟的是,它們是潛在的錯誤之源,因爲它們使代碼變得脆弱。如果有人試圖改變它們,就可能對代碼產生破壞。

因此,對於上述的例子,比較好的思路是徹底避免編寫拷貝構造函數和賦值操作符。

一般而言,有幾種方式可供選擇:

  • 依賴編譯器自動創建的默認版本
  • 把拷貝構造函數和賦值操作符聲明爲私有,並且不提供實現,禁止任何類型的複製
  • 編寫自己的版本
對於上述三種方式,應該儘量避免使用第三種。如果發現自己爲某個類編寫了拷貝構造函數或賦值操作符,思考是否有必要。也許可以避免這種做法並轉爲第一種方式(使用編譯器所創建的默認版本)或使用其他方法(例如智能指針)。如果仍然不確定,可以使用第二種方式,只要不存在任何類型的複製,就不會出錯。但是,需要注意類的有些用法(例如在vector<MyClass>中)需要拷貝構造函數和賦值操作符,因此禁止任何類型的複製也需要謹慎,必須理解它限制了類的使用方面的某些選項。

總結:

  • 只要有可能,避免編寫拷貝構造函數和賦值操作符
  • 如果默認版本並不適用,可以考慮把拷貝構造函數和賦值操作符聲明爲私有,禁止類實例的複製

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章