google C++ 程式設計規範中的禁用複製建構函式和賦值運算子
阿新 • • 發佈:2019-01-08
在google C++程式設計規範中有下面一段描述:
僅在程式碼中需要拷貝一個類物件的時候使用拷貝建構函式;不需要拷貝時應使用
DISALLOW_COPY_AND_ASSIGN。
定義:通過拷貝新建物件時可使用拷貝建構函式(特別是物件的傳值時)。
優點:拷貝建構函式使得拷貝物件更加容易,STL容器要求所有內容可拷貝、可賦值。
缺點:C++中物件的隱式拷貝是導致很多效能問題和bugs的根源。拷貝建構函式降低了
程式碼可讀性,相比按引用傳遞,跟蹤按值傳遞的物件更加困難,物件修改的地方變得難以捉
摸。
而具體的則沒有明說,今天看了《More Effective C++》之後,重新思考了這個問題。
禁用複製建構函式的原因有下面兩個(包括但不限於 :)):
1.耗時 當繼承的層次越來越深的時候,物件會越來越大,採用淺複製的話,雖然速度快,但是會有記憶體洩漏和出現野指標等風險。採用深複製的話,速度就會慢很多。而賦值運算子也是同理。 2.不安全 當使用賦值運算子的時候,考慮下面一個例子(為了便於閱讀,我把函式的定義和類的定義放在一起了):當執行下面的main函式的時候:#ifndef _HUMAN_H #define _HUMAN_H #include <cstdio> class Human { public : Human &operator=(const Human &rhs){ printf("Human &operator=(const Human &rhs)\n"); return *this; } }; class Male : public Human{ public : Male &operator= (const Human &rhs) { printf("Male &operator= (const Human &rhs)\n"); return *this; } Male &operator=(const Male &rhs) { printf("Male &operator=(const Male &rhs)\n"); return *this; } }; class Female : public Human { public : Female &operator= (const Human &rhs) { printf("Female &operator= (const Human &rhs)\n"); return *this; } Female &operator=(const Female &rhs) { printf("Female &operator=(const Female &rhs)\n"); return *this; } }; #endif // _HUMAN_H
int main() {
Human *male1 = new Male();
Human *male2 = new Female();
*male1 = *male2;
return 0;
}
呼叫的是Human &operator=(const Human &rhs)這個複製運算子。而當呼叫基類的賦值運算子的時候,只能被複制的也只是基類的部分,而真正的派生類的部分是不會被複制的,這不符合我們的語意。 如果把賦值運算子宣告為虛擬函式的話,雖然能呼叫基類中的 virtual Male &operator= (const Human &rhs)。而這個動作還是跟我們的語意不相同,我們希望的是呼叫
class NoCopyAndAssign {
public :
NoCopyAnd *clone() const = 0;
private :
NoCopyAndAssign(const NoCopyAndAssign &);
void operator=(const NoCopyAndAssign &);
};
通過clone返回一個指向已經複製的元素的指標,就可以了。如果想要更安全一點,可以把返回的指標包裝在auto_ptr型別或者其他智慧指標型別。