読者です 読者をやめる 読者になる 読者になる

C++11:デフォルト関数の生成の制御:defaultおよびdelete

C++ C++11

C++11では、「コピーを禁止する」という慣用句(イディオム)を直接表現できるようになった。

class Foo
{
    Foo(const Foo &) = delete;
    Foo &operator=(const Foo &) = delete;
    // ...
};

C++98では、private宣言して定義しないという手法がよく用いられた。

class Foo
{
  private:
    Foo(const Foo &);
    Foo &operator=(const Foo &);
    // ...
};

逆に、デフォルトの動作が望ましいなら、それを明示することもできる。

class Bar
{
    // ...
  public:
    Bar() = default;
    ~Bar() = default;
    Bar(const Bar &) = delete;
    Bar &operator=(const Bar &) = delete;
    Bar(Bar &&) = default;
    Bar &operator=(Bar &&) = default;
    // ...
};

=defaultは、デフォルトで生成されるどんな関数にでも使用でき、=deleteは、どんな関数にでも使用できる。

class D
{
    double d;
  public:
    D(double);
    D(int) = delete;
};

int main()
{
    D d1(1.2); // OK
    D d2(3);   // エラー
}

デフォルトでは、クラスに対して以下の関数が生成される。

プログラマーがこれらの関数を宣言すると、コンパイラーは次の規則に基づいて生成しない。

  1. プログラマーコンストラクターを一つでも宣言すれば、コンパイラーはデフォルトコンストラクターを生成しない。
  2. プログラマーがコピー関数、ムーブ関数、デストラクターの何れか一つでも宣言すれば、コンパイラーはコピー関数、ムーブ関数、デストラクターの何れも生成しない。

ただし、2つ目の規則は後方互換性維持のために不完全な効力しか持たず、私の環境(clang 3.4.2)ではBjarne Stroustrup氏の記事書籍とも異なるよくわからないコンパイル結果となった。
そのため、コピー関数、ムーブ関数、デストラクターの何れか一つでも宣言する場合は、その他の関数も明示的に宣言した方が良いだろう。