2014-05-17 68 views
10

我有一個問題,因爲C++ 11默認生成複製構造函數和複製賦值運算符時存在用戶定義的析構函數。在C++中禁用複製類的最簡潔的方法

對於最簡單的類,默認生成的構造函數,運算符和析構函數都很好。考慮以下原因來聲明析構函數:

  1. 使平凡的析構函數在基類的虛:

    // header 
    class Base1 { public: virtual ~Base1() = default; }; 
    class Base2 { public: virtual ~Base2(); }; 
    // source 
    Base2::~Base2() = default; 
    

    會所有4複製和移動通過編譯器在這些情況下產生的特殊的方法?如果是,那麼我認爲這很好,並且不需要使Base1Base2複雜化。在析構函數

  2. 打印調試消息:

    // header 
    class D { public: ~D(); }; 
    // source 
    D::~D() { 
    #ifdef DEBUG_THIS 
        std::cout << "D was destructed." << std::endl; 
    #endif 
    } 
    

    我認爲,在這種情況下,拷貝構造函數和賦值運算符將產生;但移動構造函數和賦值操作符不會。我想避免使用已棄用的默認生成並禁用D的複製。我也想避免洪水D與4 deleted聲明。僅禁用一個拷貝構造函數就夠了嗎?這是一種很好的風格嗎?

+0

我不明白你在討論棄用的問題。你能澄清一下嗎? – stefan

+1

在standard-C++ - land中,您只能從不可複製的類繼承,如'boost :: noncopyable'。使用Visual C++,您可能會考慮添加私有聲明的宏,以避免愚蠢警告。 –

+0

@stefan,*如果T具有用戶定義的析構函數或用戶定義的複製賦值運算符,則不推薦使用隱式定義的複製構造函數的生成。*自C++ 11以來(請參見http://en.cppreference.com/ W/CPP /語言/ copy_constructor#隱式defined_copy_constructor)。 – vedg

回答

3
  1. 只有拷貝構造函數和拷貝時,析構函數被明確默認賦值運算符將產生。即使這樣,他們的這一代也被棄用了。所以,爲了有虛析構函數和所有的默認方法,應該寫:

    struct Base 
    { 
        Base()=default; 
        virtual ~Base() = default; 
        Base(const Base&)=default; 
        Base& operator=(const Base&)=default; 
        Base(Base&&)=default; 
        Base& operator=(Base&&)=default; 
    }; 
    

    我肯定會使用宏不止一個這樣的Base類。

  2. 如果用戶定義的的析構函數仍然生成2種特殊方法。有以下幾種方式禁用棄用生成的拷貝構造函數和拷貝賦值運算符:

    • 刪除移動構造函數或移動賦值運算符(不太言自明,但時間很短):

      Base(Base&&)=delete; // shorter than deleting assignment operator 
      
    • 刪除均爲拷貝構造函數和拷貝賦值操作符:

      Base(const Base&)=delete; 
      Base& operator=(const Base&)=delete; 
      

    請注意,如果需要它,您必須顯式聲明默認構造函數。 Base()=default;

    宏或繼承特殊類也可以用於此目的,但我個人更喜歡刪除移動構造函數來實現我自己的宏或基類。當使用Qtboost時,我更喜歡Q_DISABLE_COPY(Base),並且分別繼承boost::noncopyable,因爲它們已經實現,廣爲人知和可識別。

http://accu.org/index.php/journals/1896 - 這些問題的詳細解釋和基本原理。

9

刪除拷貝構造函數和拷貝賦值運算符是禁止複製的最簡單和最清晰的方式:

class X 
{ 
    X(X const &) = delete; 
    void operator=(X const &x) = delete; 
}; 

我不跟着你,在這個問題虛析構函數在說什麼身體 。這聽起來像是在尋求一種讓代碼佔用更少的源代碼字符的方法,但對於任何查看它的人來說也更加神祕。

如果刪除的函數列表困擾您,我想可以將它們隱藏在宏後面。

#define NON_COPYABLE_NOR_MOVABLE(T) \ 
     T(T const &) = delete; \ 
     void operator=(T const &t) = delete; \ 
     T(T &&) = delete; 
+1

如果你沒有使用支持'= delete'語法的編譯器,我強烈建議使用這個宏。它不僅更具可讀性(對代碼一瞥而言有幫助),但它也是可搜索的*,以某種私有函數列表的方式進行搜索。 –

+0

1.通常需要爲繼承的類提供虛擬析構函數。我問是否所有4個默認的構造函數/賦值操作符都會爲'Base1'和'Base2'生成。如果*是*,則不需要顯式聲明或刪除它們中的任何一個(如果沒有其他非一致性原因禁用複製或移動)。 – vedg

+0

2.是否顯式刪除只有一個拷貝構造函數足夠?或者可能顯式刪除移動構造函數?從答案和評論看,恐怕有必要顯式刪除至少2種特殊方法(樣板或宏或繼承):( – vedg

10

用C++ 11,一個乾淨的方法是按照升壓所用的模式(見here

基本上,你創建一個基類,其中拷貝構造函數和拷貝賦值被刪除,它繼承:

class non_copyable 
{ 
protected: 
    non_copyable() = default; 
    ~non_copyable() = default; 

    non_copyable(non_copyable const &) = delete; 
    void operator=(non_copyable const &x) = delete; 
}; 

class MyClass: public non_copyable 
{ 
... 
} 
+1

)爲了使這個'non_copyable'類通常可用,您需要添加相關的特殊成員函數現在沒有生成 –

+0

真的,編輯過,謝謝 – quantdev

+0

我同意在大量小類的情況下繼承'non_copyable'是一個好主意,但是(我的問題的標題)!=(整個問題)。實際上有幾個問題,其中大多數仍然沒有答案。 – vedg

相關問題