プログラミング言語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