C++11:デフォルト関数の生成の制御:defaultおよびdelete
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); // エラー }
デフォルトでは、クラスに対して以下の関数が生成される。
- デフォルトコンストラクター:X()
- コピーコンストラクター:X(const X &)
- コピー代入:X &operator=(const X &)
- ムーブコンストラクター:X(X &&)
- ムーブ代入:X &operator=(X &&)
- デストラクター:~X()
プログラマーがこれらの関数を宣言すると、コンパイラーは次の規則に基づいて生成しない。
- プログラマーがコンストラクターを一つでも宣言すれば、コンパイラーはデフォルトコンストラクターを生成しない。
- プログラマーがコピー関数、ムーブ関数、デストラクターの何れか一つでも宣言すれば、コンパイラーはコピー関数、ムーブ関数、デストラクターの何れも生成しない。
ただし、2つ目の規則は後方互換性維持のために不完全な効力しか持たず、私の環境(clang 3.4.2)ではBjarne Stroustrup氏の記事・書籍とも異なるよくわからないコンパイル結果となった。
そのため、コピー関数、ムーブ関数、デストラクターの何れか一つでも宣言する場合は、その他の関数も明示的に宣言した方が良いだろう。
参考
- control of defaults: default and delete(既定動作の制御: default と delete)
- control of defaults: move and copy(既定動作の制御: 移動とコピー)
- 作者: ビャーネ・ストラウストラップ,Bjarne Stroustrup,柴田望洋
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2015/02/28
- メディア: 大型本
- この商品を含むブログ (8件) を見る