yohhoyの日記

技術的メモをしていきたい日記

特殊メンバ関数とコンパイラによる暗黙宣言

プログラミング言語C++における特殊メンバ関数(special member functions)のユーザ宣言/コンパイラ暗黙宣言に関するメモ。本記事の内容はACCU 2014でのHoward Hinnant氏プレゼン(PDF) "Everything You Ever Wanted To Know About Move Semantics (and then some)" に基づく。

下記6つが特殊メンバ関数として扱われる。これらのメンバ関数は、“宣言なし”、“暗黙の宣言(defaulted/deleted)”、“ユーザ宣言(=default/=delete/ユーザ定義)”のいずれかとなる。

デフォルト・コンストラク X()
デストラク ~X()
コピー・コンストラク X(const X&)
コピー代入演算子 X& operator=(const X&)
ムーブ・コンストラク X(X&&)
ムーブ代入演算子 X& operator=(X&&)


C++11以降

C++11以降の言語仕様において、明示的に特殊メンバ関数をユーザ宣言したとき(行)、コンパイラによって生成される暗黙の宣言(列)を下表に示す。

デフォルト
コンストラク
デストラク コピー
コンストラク
コピー
代入演算子
ムーブ
コンストラク
ムーブ
代入演算子
(ユーザ宣言しない) defaulted defaulted defaulted defaulted defaulted defaulted
(任意のコンストラクタ) 宣言なし defaulted defaulted defaulted defaulted defaulted
デフォルト
コンストラク
ユーザ宣言 defaulted defaulted defaulted defaulted defaulted
デストラク defaulted ユーザ宣言 (defaulted) (defaulted) 宣言なし 宣言なし
コピー
コンストラク
宣言なし defaulted ユーザ宣言 (defaulted) 宣言なし 宣言なし
コピー
代入演算子
defaulted defaulted (defaulted) ユーザ宣言 宣言なし 宣言なし
ムーブ
コンストラク
宣言なし defaulted deleted deleted ユーザ宣言 宣言なし
ムーブ
代入演算子
defaulted defaulted deleted deleted 宣言なし ユーザ宣言
  • 任意のコンストラクタ(コピー/ムーブを含む)をユーザ宣言するとき、デフォルト・コンストラクタは暗黙に宣言されない。
  • デストラクタ、コピー・コンストラクタ/代入演算子、ムーブ・コンストラクタ/代入演算子をユーザ宣言するとき、ムーブ・コンストラクタ/代入演算子は暗黙に宣言されない。
  • ムーブ・コンストラクタ/代入演算子をユーザ宣言するとき、コピー・コンストラクタ/代入演算子は暗黙にdeleted宣言される。

デストラクタ、コピー・コンストラクタ/代入演算子をユーザ宣言するとき、コピー・コンストラクタ/代入演算子はdefaulted宣言される。この暗黙のdefaulted宣言は非推奨(deprecated)である(表中では"(defaulted)")ため、デストラクタをユーザ宣言する場合は同時にコピー・コンストラクタ/代入演算子もユーザ宣言すること。

struct X {
// デストラクタをユーザ宣言するとき、
  ~X() {...}
// NG: コンパイラは下記を暗黙宣言するが、この動作は非推奨!
  // X(const X&) = default;
  // X& operator=(const X&) = default;
};

C++11(N3337) 12.8/p7, 18より一部引用(下線部は強調)。

7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. (snip)

18 If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor. (snip)

C++03以前

C++03以前の言語仕様において、明示的に特殊メンバ関数をユーザ宣言したとき(行)、コンパイラによって生成される暗黙の宣言(列)を下表に示す。

デフォルト
コンストラク
デストラク コピー
コンストラク
コピー
代入演算子
(ユーザ宣言しない) defaulted defaulted defaulted defaulted
(任意のコンストラクタ) 宣言なし defaulted defaulted defaulted
デフォルト
コンストラク
ユーザ宣言 defaulted defaulted defaulted
デストラク defaulted ユーザ宣言 defaulted defaulted
コピー
コンストラク
宣言なし defaulted ユーザ宣言 defaulted
コピー
代入演算子
defaulted defaulted defaulted ユーザ宣言

関連URL