Constructors and member initializer lists
コンストラクタ は、特別な宣言子構文で宣言される非静的 メンバー関数 であり、それらのクラス型のオブジェクトを初期化するために使用されます。
|
コンストラクタは コルーチン にすることはできません。 |
(C++20以降) |
|
コンストラクタは 明示的なオブジェクトパラメータ を持つことはできません。 |
(C++23以降) |
、
、
目次 |
構文
コンストラクタは、以下の形式のメンバー function declarators を使用して宣言されます:
class-name
(
parameter-list
(オプション)
)
except
(オプション)
attr
(オプション)
|
|||||||||
| class-name | - | 識別子式、 属性のリストが続く可能性があり、そして (C++11以降) 括弧の組で囲まれる可能性がある | ||||||
| parameter-list | - | パラメータリスト | ||||||
| except | - |
|
||||||
| attr | - | (C++11以降) 属性のリスト |
コンストラクタ宣言の
宣言指定子
で許可されている唯一の指定子は
friend
、
inline
、
constexpr
(C++11以降)
、
consteval
(C++20以降)
、および
explicit
です(特に、戻り値型は許可されません)。
CV修飾子と参照修飾子
も許可されないことに注意してください:構築中のオブジェクトのconstおよびvolatileセマンティクスは、最も派生したコンストラクタの完了後にのみ有効になります。
class-name の識別子式は、以下のいずれかの形式でなければなりません:
- friend宣言 において、識別子式は 修飾識別子 であり、 コンストラクタを指す 場合。
- それ以外の場合、クラスまたはクラステンプレートの メンバー仕様 に属するメンバー宣言において:
-
- クラスに対しては、識別子式は injected-class-name である直近の外側のクラスです。
- クラステンプレートに対しては、識別子式は current instantiation を指すクラス名 (C++20まで) injected-class-name (C++20以降) である直近の外側のクラステンプレートです。
- それ以外の場合、識別子式は、その ルックアップ コンテキストの注入クラス名が終端非修飾識別子である修飾識別子です。
メンバー初期化子リスト
クラス
T
の任意のコンストラクタの
関数定義
の本体は、複合ステートメントの開き括弧の前に、
メンバ初期化子リスト
を含むことができます。その構文はコロン文字
:
の後に、1つ以上の
member-initializer
をカンマ区切りで並べたもので、それぞれは以下の構文を持ちます:
| メンバ 初期化子 | (1) | ||||||||
| クラス 初期化子 | (2) | ||||||||
クラスパック
初期化子
...
|
(3) | (C++11以降) | |||||||
|
(C++11以降) |
-
Tの直接基底クラスまたは virtual base class 。この場合、対応する基底クラス部分オブジェクトは initializer で直接初期化される。
| member | - | データメンバを命名する識別子 |
| class | - | クラス名 |
| class-pack | - | 0個以上のクラスに展開されるパック |
| initializer | - |
=
で始まらない
initializer
|
struct S { int n; S(int); // コンストラクタ宣言 S() : n(7) {} // コンストラクタ定義: // ": n(7)" は初期化子リスト // ": n(7) {}" は関数本体 }; S::S(int x) : n{x} {} // コンストラクタ定義: ": n{x}" は初期化子リスト int main() { S s; // S::S() を呼び出し S s2(10); // S::S(int) を呼び出し }
説明
コンストラクタには名前がなく、直接呼び出すことはできません。これらは 初期化 が行われる際に呼び出され、初期化の規則に従って選択されます。 explicit 指定子を持たないコンストラクタは converting constructors です。 constexpr 指定子を持つコンストラクタはその型を literal type にします。引数なしで呼び出すことができるコンストラクタは default constructors です。同じ型の別のオブジェクトを引数として取るコンストラクタは copy constructors と move constructors です。
コンストラクタの関数本体を形成する複合文の実行が開始される前に、すべての直接基底クラス、仮想基底クラス、および非静的データメンバーの初期化が完了します。メンバー初期化子リストは、これらのサブオブジェクトの非デフォルト初期化を指定する場所です。デフォルト初期化できない基底クラスや、デフォルト初期化 または デフォルトメンバー初期化子 によって初期化できない非静的データメンバー(存在する場合) (C++11以降) 、例えば参照型やconst修飾型のメンバーなどについては、メンバー初期化子を指定する必要があります。 (クラステンプレートのインスタンス化における非静的データメンバーのデフォルトメンバー初期化子は、メンバーの型または初期化子が依存型の場合、無効となる可能性があることに注意してください。) (C++11以降) メンバー初期化子 またはデフォルトメンバー初期化子 (C++11以降) を持たない 匿名共用体 または バリアントメンバー に対しては初期化は実行されません。
初期化子( class が仮想基底クラスを指定する場合)は、構築中のオブジェクトの最も派生したクラスではない任意のクラスの構築中は無視されます。
initializer 内に現れる名前はコンストラクタのスコープで評価されます:
class X { int a, b, i, j; public: const int& r; X(int i) : r(a) // X::r を X::a への参照として初期化 , b{i} // X::b をパラメータ i の値で初期化 , i(i) // X::i をパラメータ i の値で初期化 , j(this->i) // X::j を 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) {} // エラー const int& v; };
注: 同じことが default member initializer にも適用されます。
構築および破棄中の操作
構築中または破棄中のオブジェクトに対して、メンバー関数(
仮想メンバー関数
を含む)を呼び出すことができます。同様に、構築中または破棄中のオブジェクトは
typeid
または
dynamic_cast
のオペランドとなることができます。
ただし、以下の評価のいずれかでこれらの操作が実行される場合、動作は未定義です:
| (C++26以降) |
- 基底クラスのすべての member-initializer が完了する前に メンバ初期化子リストが評価されること
委譲コンストラクタメンバ初期化子リストにおいてクラス名自体が class-or-identifier として現れる場合、そのリストはその単一のメンバ初期化子のみで構成されなければならない。このようなコンストラクタは 委譲コンストラクタ として知られ、初期化子リストの唯一のメンバによって選択されるコンストラクタは ターゲットコンストラクタ と呼ばれる。 この場合、ターゲットコンストラクタはオーバーロード解決によって選択され最初に実行され、その後制御が委譲コンストラクタに戻りその本体が実行される。 委譲コンストラクタは再帰的であってはならない。 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}, // 基底クラスの初期化 x(x), // x(メンバ)はx(パラメータ)で初期化 y{0}, // yは0で初期化 f{"test.cc", std::ios::app}, // これはmとlgの初期化後に実行される s(__func__), // 初期化リストはコンストラクタの一部なので__func__が利用可能 lg(m), // lgは既に初期化済みのmを使用 m{} // ここでは最後に現れるが、mはlgより先に初期化される {} // 空の複合文 Class(double a) : y(a + 1), x(y), // xはyより先に初期化されるため、ここの値は不定 lg(m) {} // 基底クラスの初期化子はリストに現れないため // デフォルト初期化される(Base()を使用した場合の値初期化とは異なる) Class() try // 関数tryブロックは関数本体(初期化リストを含む)の前に開始 : Class(0.0) // 委譲コンストラクタ { // ... } catch (...) { // 初期化中に例外が発生 } }; 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規格 (ISO/IEC 14882:2020):
-
- 11.4.4 コンストラクタ [class.ctor]
-
- 11.10.2 基底クラスとメンバの初期化 [class.base.init]
- C++17規格 (ISO/IEC 14882:2017):
-
- 15.1 コンストラクタ [class.ctor]
-
- 15.6.2 基底クラスとメンバの初期化 [class.base.init]
- C++14 標準 (ISO/IEC 14882:2014):
-
- 12.1 コンストラクタ [class.ctor]
-
- 12.6.2 基底クラスとメンバの初期化 [class.base.init]
- C++11標準 (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]