【C++】DISALLOW_COPY_AND_ASSIGN


有時候,進行類體設計時,會發現某個類的對象是獨一無二的,沒有完全相同的對象,也就是對該類對象做副本沒有任何意義.

因此,需要限制編譯器自動生動的拷貝構造函數和賦值構造函數.一般參用下面的宏定義的方式進行限制,代碼如下:

// A macro to disallow the copy constructor and operator= functions 
// This should be used in the priavte:declarations for a class
#define    DISALLOW_COPY_AND_ASSIGN(TypeName) \
    TypeName(const TypeName&);                \
    TypeName& operator=(const TypeName&)

class Test {
public:
    Test(int t);
    ~Test();
private:
    DISALLOW_COPY_AND_ASSIGN(Test);
};

聲明私有的拷貝構造函數和賦值構造函數,但不去定義實現它們,有三方面的作用:

1.聲明了拷貝構造函數和賦值函數,阻止了編譯器暗自創建的專屬版本.

2.聲明了private,阻止了外部對它們的調用.

3.不定義它們,可以保證成員函數和友元函數調用它們時,產生一個連接錯誤.

上述解決方法,面對在成員函數和友元函數企圖拷貝對象時,會產生連接器錯誤.

遵循錯誤發現越早越好的原則,我們希望將連接期錯誤移至編譯期.

解決思路是:設計一個專門為了阻止copying動作(包含copy和assign)而設計的基類

class Uncopyable {
protected:
    Uncopyable() {}
    ~Uncopyable() {}
private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator=(const Uncopyable&);
};
class Test:private Uncopyable{
...                            //class不再聲明copy構造函數或copy assignment操作符
};

如上述代碼,當任何人(包括member函數或friend函數)嘗試拷貝Test對象時,編譯器便試着生成一個copy構造函數和一個copy assignment操作符.

編譯器自動生成這些函數時,會調用其基類的對應函數,而基類中這些函數是private,因而那些調用會被編譯器拒絕,產生編譯器錯誤.

像Uncopyable這樣的基類,沒有non-static成員變量,沒有virtual函數,也沒有virtual base classes,可以滿足空白基類最優化的條件(empty base optimization)

這類基類的派生類,不會繼承的關系而產生多余的空間存儲.

class Empty {};
class HoldsAnInt:private empty {
private:
    int x;
};
sizeof(HoldsAnInt) == sizeof(int)

這種解決方法不足之處是會導致多重繼承,而多重繼承有時會阻止empty base optimization,將會引入多余的空間存儲.

啟發:針對具體的應用,其類的用途和性質要分析清楚,從而選擇更合適的設計方法.

設計的過程,就是一個權衡的過程,有時候這種方法好,有時候另一種方法好,需要與具本應用結合,從而折中選擇.

參考資料:Effective C++


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM