名前空間
変種
操作

コンストラクタとメンバ初期化子リスト

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス宣言
コンストラクタ
thisポインタ
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

コンストラクタは、特殊な宣言子構文で宣言された非静的メンバー関数であり、そのクラス型のオブジェクトを初期化するために使用されます。

コンストラクタはコルーチンにすることはできません。

(C++20以降)

コンストラクタは明示的オブジェクトパラメータを持つことはできません。

(C++23から)

目次

[編集] 構文

コンストラクタは、以下の形式のメンバー関数宣言子を使用して宣言されます。

クラス名 ( パラメータリスト (オプション) ) except (オプション) attr (オプション)
class-name - 識別子式任意で属性のリストが続き、(C++11以降)任意で括弧のペアで囲まれます。
parameter-list - パラメータリスト
except -

動的例外仕様

(C++11まで)

動的例外指定
またはnoexcept指定

(C++11以降)
(C++17まで)

noexcept指定

(C++17以降)
attr - (C++11以降) 属性のリスト

コンストラクタ宣言の宣言指定子で許可される指定子は、friendinlineconstexpr(C++11以降)consteval(C++20以降)、およびexplicitのみです(特に、戻り型は許可されません)。cv-修飾子および参照修飾子も許可されないことに注意してください。構築中のオブジェクトのconstおよびvolatileセマンティクスは、最も派生したコンストラクタが完了した後にのみ適用されます。

クラス名の識別子式は、次のいずれかの形式である必要があります。

  • クラスの場合、識別子式は直近の外側のクラスの注入クラス名です。
  • クラステンプレートの場合、識別子式は現在のインスタンス化を指すクラス名(C++20まで)直近の外側のクラステンプレートの注入クラス名(C++20以降)です。
  • それ以外の場合、識別子式は、その検索コンテキストの注入クラス名である末端の非修飾識別子を持つ修飾識別子です。

[編集] メンバー初期化子リスト

コンストラクタの関数定義の本体は、複合ステートメントの開始中括弧の前に、メンバー初期化子リストを含むことができます。その構文はコロン文字:に続き、コンマ区切りの1つ以上のメンバー初期化子のリストであり、それぞれは以下の構文を持ちます。

クラス名または識別子 ( 式リスト (オプション) ) (1)
クラス名または識別子 中括弧初期化子リスト (2) (C++11以降)
パラメータパック ... (3) (C++11以降)
1) クラス名または識別子で指定された基底またはメンバーを直接初期化で初期化します。または、式リストが空の場合、値初期化で初期化します。
2) クラス名または識別子で指定された基底またはメンバーをリスト初期化で初期化します(リストが空の場合は値初期化となり、集約を初期化する場合は集約初期化となります)。
3) パック展開を使用して複数の基底を初期化します。
クラス名または識別子 - 非静的データメンバーの名前、またはクラス自体(委譲コンストラクタの場合)または直接または仮想基底の名前である型名を表す識別子。
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以降)

[編集] 初期化順序

リスト内のメンバー初期化子の順序は無関係です。実際の初期化順序は次のとおりです。

1) コンストラクタが最も派生したクラスのものである場合、仮想基底は基底クラス宣言の深さ優先左から右への走査で現れる順序で初期化されます(左から右は基底指定子リストにおける出現順序を指します)。
2) 次に、直接基底はこのクラスの基底指定子リストに現れる順序で左から右に初期化されます。
3) 次に、非静的データメンバーはクラス定義内の宣言順序で初期化されます。
4) 最後に、コンストラクタの本体が実行されます。

(注:初期化順序が異なるコンストラクタのメンバー初期化子リストにおける出現順序によって制御されていた場合、デストラクタは破棄順序が構築順序の逆であることを保証できませんでした。)

[編集] ノート

機能テストマクロ 規格 機能
__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]

[編集] 関連項目

English 日本語 中文(简体) 中文(繁體)