コンストラクタとメンバ初期化子リスト
コンストラクタは、特殊な宣言子構文で宣言された非静的メンバー関数であり、そのクラス型のオブジェクトを初期化するために使用されます。
|
コンストラクタはコルーチンにすることはできません。 |
(C++20以降) |
|
コンストラクタは明示的オブジェクトパラメータを持つことはできません。 |
(C++23から) |
目次 |
[編集] 構文
コンストラクタは、以下の形式のメンバー関数宣言子を使用して宣言されます。
クラス名 ( パラメータリスト (オプション) ) except (オプション) attr (オプション) |
|||||||||
| class-name | - | 識別子式。任意で属性のリストが続き、(C++11以降)任意で括弧のペアで囲まれます。 | ||||||
| parameter-list | - | パラメータリスト | ||||||
| except | - |
| ||||||
| attr | - | (C++11以降) 属性のリスト |
コンストラクタ宣言の宣言指定子で許可される指定子は、friend、inline、constexpr(C++11以降)、consteval(C++20以降)、およびexplicitのみです(特に、戻り型は許可されません)。cv-修飾子および参照修飾子も許可されないことに注意してください。構築中のオブジェクトのconstおよびvolatileセマンティクスは、最も派生したコンストラクタが完了した後にのみ適用されます。
クラス名の識別子式は、次のいずれかの形式である必要があります。
- クラスの場合、識別子式は直近の外側のクラスの注入クラス名です。
- クラステンプレートの場合、識別子式は現在のインスタンス化を指すクラス名(C++20まで)直近の外側のクラステンプレートの注入クラス名(C++20以降)です。
- それ以外の場合、識別子式は、その検索コンテキストの注入クラス名である末端の非修飾識別子を持つ修飾識別子です。
[編集] メンバー初期化子リスト
コンストラクタの関数定義の本体は、複合ステートメントの開始中括弧の前に、メンバー初期化子リストを含むことができます。その構文はコロン文字:に続き、コンマ区切りの1つ以上のメンバー初期化子のリストであり、それぞれは以下の構文を持ちます。
クラス名または識別子 ( 式リスト (オプション) ) |
(1) | ||||||||
| クラス名または識別子 中括弧初期化子リスト | (2) | (C++11以降) | |||||||
パラメータパック ... |
(3) | (C++11以降) | |||||||
| クラス名または識別子 | - | 非静的データメンバーの名前、またはクラス自体(委譲コンストラクタの場合)または直接または仮想基底の名前である型名を表す識別子。 |
| expression-list (式リスト) | - | 基底またはメンバーのコンストラクタに渡す引数の、空の可能性のあるコンマ区切りリスト。 |
| 中括弧初期化子リスト | - | 中括弧で囲まれた初期化子リスト。 |
| パラメータパック | - | 可変引数テンプレートパラメータパックの名前。 |
struct S { int n; S(int); // constructor declaration S() : n(7) {} // constructor definition: // ": n(7)" is the initializer list // ": n(7) {}" is the function body }; S::S(int x) : n{x} {} // constructor definition: ": n{x}" is the initializer list int main() { S s; // calls S::S() S s2(10); // calls S::S(int) }
[編集] 説明
コンストラクタには名前がなく、直接呼び出すことはできません。初期化が行われる際に呼び出され、初期化の規則に従って選択されます。explicit指定子のないコンストラクタは変換コンストラクタです。constexpr指定子を持つコンストラクタは、その型をリテラル型にします。引数なしで呼び出すことができるコンストラクタはデフォルトコンストラクタです。同じ型の別のオブジェクトを引数として取るコンストラクタはコピーコンストラクタとムーブコンストラクタです。
コンストラクタの関数本体を形成する複合ステートメントが実行を開始する前に、すべての直接基底、仮想基底、および非静的データメンバーの初期化が完了します。メンバー初期化子リストは、これらのサブオブジェクトの非デフォルト初期化を指定できる場所です。デフォルト初期化できない基底や、デフォルト初期化またはデフォルトメンバー初期化子(存在する場合)で初期化できない(C++11以降)、参照型やconst修飾型のメンバーなどの非静的データメンバーには、メンバー初期化子を指定する必要があります。(クラステンプレートインスタンスの非静的データメンバーのデフォルトメンバー初期化子は、メンバー型または初期化子が依存的である場合、無効になる可能性があることに注意してください。)(C++11以降)メンバー初期化子またはデフォルトメンバー初期化子(C++11以降)を持たない無名共用体やバリアントメンバーに対しては、初期化は行われません。
クラス名または識別子が仮想基底クラスを指す初期化子は、構築中のオブジェクトの最も派生したクラスではないクラスの構築中は無視されます。
式リストまたは中括弧初期化子リストに現れる名前は、コンストラクタのスコープで評価されます。
class X { int a, b, i, j; public: const int& r; X(int i) : r(a) // initializes X::r to refer to X::a , b{i} // initializes X::b to the value of the parameter i , i(i) // initializes X::i to the value of the parameter i , j(this->i) // initializes X::j to the value of X::i {} };
メンバー初期化子からスローされた例外は、関数tryブロックで処理できます。
|
非静的データメンバーがデフォルトメンバー初期化子を持ち、かつメンバー初期化子リストにも現れる場合、メンバー初期化子が使用され、デフォルトメンバー初期化子は無視されます。 struct S { int n = 42; // default member initializer S() : n(7) {} // will set n to 7, not 42 }; |
(C++11以降) |
参照メンバーは、メンバー初期化子リスト内で一時オブジェクトにバインドすることはできません。
struct A { A() : v(42) {} // Error const int& v; };
注:デフォルトメンバー初期化子にも同様に適用されます。
[編集] 構築中と破棄中の操作
構築中または破棄中のオブジェクトに対して、メンバー関数(仮想メンバー関数を含む)を呼び出すことができます。同様に、構築中または破棄中のオブジェクトは、typeidまたはdynamic_castのオペランドにすることができます。
ただし、これらの操作が以下のいずれかの評価中に実行された場合、動作は未定義です。
|
(C++26以降) |
- 基底クラスのすべてのメンバー初期化子が完了する前のメンバー初期化子リストの評価。
委譲コンストラクタメンバー初期化子リストでクラス自身の名前がクラス名または識別子として現れる場合、リストはその1つのメンバー初期化子のみで構成されなければなりません。このようなコンストラクタは委譲コンストラクタとして知られ、初期化子リストの唯一のメンバーによって選択されたコンストラクタはターゲットコンストラクタです。 この場合、ターゲットコンストラクタはオーバーロード解決によって選択され、最初に実行され、その後制御は委譲コンストラクタに戻り、その本体が実行されます。 委譲コンストラクタは再帰的であってはなりません。 class Foo { public: Foo(char x, int y) {} Foo(int y) : Foo('a', y) {} // Foo(int) delegates to Foo(char, int) }; 継承コンストラクタusing宣言を参照。 |
(C++11以降) |
[編集] 初期化順序
リスト内のメンバー初期化子の順序は無関係です。実際の初期化順序は次のとおりです。
(注:初期化順序が異なるコンストラクタのメンバー初期化子リストにおける出現順序によって制御されていた場合、デストラクタは破棄順序が構築順序の逆であることを保証できませんでした。)
[編集] ノート
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_delegating_constructors |
200604L |
(C++11) | 委譲コンストラクタ |
[編集] 例
#include <fstream> #include <string> #include <mutex> struct Base { int n; }; struct Class : public Base { unsigned char x; unsigned char y; std::mutex m; std::lock_guard<std::mutex> lg; std::fstream f; std::string s; Class(int x) : Base{123}, // initialize base class x(x), // x (member) is initialized with x (parameter) y{0}, // y initialized to 0 f{"test.cc", std::ios::app}, // this takes place after m and lg are initialized s(__func__), // __func__ is available because init-list is a part of constructor lg(m), // lg uses m, which is already initialized m{} // m is initialized before lg even though it appears last here {} // empty compound statement Class(double a) : y(a + 1), x(y), // x will be initialized before y, its value here is indeterminate lg(m) {} // base class initializer does not appear in the list, it is // default-initialized (not the same as if Base() were used, which is value-init) Class() try // function try block begins before the function body, which includes init list : Class(0.0) // delegate constructor { // ... } catch (...) { // exception occurred on initialization } }; int main() { Class c; Class c1(1); Class c2(0.1); }
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 194 | C++98 | コンストラクタの宣言子構文は 最大1つの関数指定子のみを許可していた(例:コンストラクタは inline explicitと宣言できなかった) |
複数の関数 指定子が許可された |
| CWG 257 | C++98 | 抽象クラスが仮想基底クラスのメンバー初期化子を 提供すべきか否かが不明確であった |
不要と指定された そして、そのようなメンバー初期化子 は実行中に無視される |
| CWG 263 | C++98 | コンストラクタの宣言子構文は コンストラクタがフレンドであることを禁止していた |
コンストラクタが フレンドとなることを許可した |
| CWG 1345 | C++98 | デフォルトメンバー初期化子のない無名共用体メンバーは デフォルト初期化されていた |
初期化されない |
| CWG 1435 | C++98 | コンストラクタの宣言子構文における「クラス名」の意味が 不明確であった |
構文を特殊な 関数宣言子構文に変更した |
| CWG 1696 | C++98 | 参照メンバーは一時オブジェクトに初期化可能であった (その寿命はコンストラクタの終わりで終了する) |
そのような初期化は 不正な形式である |
[編集] 参照
- C++23標準 (ISO/IEC 14882:2024)
- 11.4.5 コンストラクタ [class.ctor]
- 11.9.3 基底とメンバーの初期化 [class.base.init]
- C++20 standard (ISO/IEC 14882:2020)
- 11.4.4 コンストラクタ [class.ctor]
- 11.10.2 基底とメンバーの初期化 [class.base.init]
- C++17 standard (ISO/IEC 14882:2017)
- 15.1 コンストラクタ [class.ctor]
- 15.6.2 基底とメンバーの初期化 [class.base.init]
- C++14 standard (ISO/IEC 14882:2014)
- 12.1 コンストラクタ [class.ctor]
- 12.6.2 基底とメンバーの初期化 [class.base.init]
- C++11 standard (ISO/IEC 14882:2011)
- 12.1 コンストラクタ [class.ctor]
- 12.6.2 基底とメンバーの初期化 [class.base.init]
- C++98 標準 (ISO/IEC 14882:1998)
- 12.1 コンストラクタ [class.ctor]
- 12.6.2 基底とメンバーの初期化 [class.base.init]