web-dev-qa-db-ja.com

C ++ 11でクラスのコピーを無効にする最も簡潔な方法

ユーザー定義のデストラクタがある場合、C++ 11のデフォルトのコピーコンストラクタとコピー代入演算子のデフォルト生成以降、非推奨の処理に問題があります。

最も十分に単純なクラスでは、デフォルトで生成されたコンストラクタ、演算子、デストラクタで十分です。デストラクタを宣言する次の理由を考慮してください。

  1. 基本クラスで自明なデストラクタを仮想化する:

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

    これらの場合、4つのコピーと移動の特殊メソッドはすべてコンパイラーによって生成されますか?はいの場合、それで問題ないと思います。複雑にする必要はありませんBase1またはBase2

  2. デストラクタにデバッグメッセージを出力する:

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

    この場合、コピーコンストラクターと代入演算子が生成されると思います。しかし、移動コンストラクタと代入演算子はそうしません。非推奨のデフォルト生成の使用を避け、Dのコピーを無効にしたい。また、Dを4つのdeleted宣言で溢れさせないようにします。 1つのコピーコンストラクターを無効にするだけで十分ですか?いいスタイルですか?

19
vedg
  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つの特別なメソッドが生成されます。 disable非推奨の生成コピーコンストラクターとコピー割り当て演算子を生成するには、次の方法があります。

    • 削除移動コンストラクターOR移動代入演算子(説明は完全ではありませんが、非常に短い):

      Base(Base&&)=delete; // shorter than deleting assignment operator
      
    • 削除両方コピーコンストラクターとコピー代入演算子:

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

    デフォルトのコンストラクタが必要な場合は、明示的に宣言する必要があることに注意してください。 Base()=default;

    マクロまたは継承する特殊クラスもこの目的で使用できますが、私は自分のマクロまたは基本クラスを実装するよりも、移動コンストラクターを削除する方を好みます。 Qtまたはboostを使用する場合、Q_DISABLE_COPY(Base)およびboost::noncopyableを継承しています。これらはすでに実装されており、広く知られ、認識されているためです。

http://accu.org/index.php/journals/1896 -これらの問題の詳細な説明と根拠。

7
vedg

C++ 11では、ブーストで使用されるパターンに従うのがクリーンな方法です( ここ を参照)。

基本的には、コピーコンストラクターとコピー割り当てが削除された基本クラスを作成し、それを継承します。

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
{
...
}
16
quantdev

コピーコンストラクターとコピー割り当て演算子を削除することは、コピーを無効にする最も簡単で明確な方法です。

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;
12
M.M

あなたはこれでそれを行うことができます(これは Caffe:ディープラーニング用の高速オープンフレームワーク によって使用されます):

// Disable the copy and assignment operator for a class.
#define DISABLE_COPY_AND_ASSIGN(classname) \
private:\
  classname(const classname&);\
  classname& operator=(const classname&)

使用例:

class CNoCopyable{

    public:
        CNoCopyable(int i):m_d(i){}

    private:
        int m_d;
        // add this line(pass class name)
        DISABLE_COPY_AND_ASSIGN(CNoCopyable);

};
1
Jayhello