デフォルト初期化
これは、初期化子なしでオブジェクトが構築されるときに実行される初期化です。
目次 |
[編集] 構文
T object ; |
(1) | ||||||||
new T |
(2) | ||||||||
[編集] 解説
デフォルト初期化は3つの状況で実行されます。
デフォルト初期化の効果は次のとおりです。
Tが (cv修飾子が付いている可能性のある) 非POD(C++11まで) クラス型である場合、コンストラクタが考慮され、空の引数リストに対してオーバーロード解決が実行されます。選択されたコンストラクタ (これはデフォルトコンストラクタの1つです) が、新しいオブジェクトの初期値を提供するために呼び出されます;Tが配列型である場合、配列のすべての要素がデフォルト初期化されます;- それ以外の場合、初期化は実行されません (注を参照)。
[編集] const オブジェクトのデフォルト初期化
プログラムがconst修飾型Tのオブジェクトのデフォルト初期化を要求する場合、Tはconst-default-constructibleなクラス型またはその配列でなければなりません。
クラス型Tは、Tのデフォルト初期化がTのユーザー提供コンストラクタ (基底クラスから継承されたものではない)(C++11以降) を呼び出す場合、または以下の場合にconst-default-constructibleです。
|
初期化子が使用されていない場合、自動ストレージ期間を持つ (cv修飾子が付いている可能性のある) 非PODクラス型 (またはその配列) のみがデフォルト初期化されると見なされていました。スカラー型と動的ストレージ期間を持つPOD型は初期化されないと見なされていました (C++11以降、この状況はデフォルト初期化の一種として再分類されました)。 |
(C++11まで) |
|
(C++11まで) |
|
(C++11以降) |
T の各潜在的に構築される基底クラスが const-default-constructibleであること。
[編集] 不定値とエラー値
|
自動または動的ストレージ期間を持つオブジェクトのストレージが取得されるとき、そのオブジェクトは不定値を持ちます。 オブジェクトに対して初期化が実行されない場合、そのオブジェクトはその値が置き換えられるまで不定値を保持します。 |
(C++26まで) |
|
自動または動的ストレージ期間を持つオブジェクトのストレージが取得されるとき、そのオブジェクトのストレージを構成するバイトは、以下の初期値をとります。
オブジェクト (そのサブオブジェクトを含む) に対して初期化が実行されない場合、そのようなバイトはその値が置き換えられるまで初期値を保持します。
|
(C++26以降) |
評価が不定値を生成する場合、動作は未定義です。
|
評価がエラー値を生成する場合、動作はエラーです。 |
(C++26以降) |
[編集] 特殊なケース
以下の型は未初期化対応 (uninitialized-friendly)です。
| (C++17以降) |
- unsigned char
-
char, その基底型がunsigned charの場合
不定またはエラー(C++26以降)値 value が与えられた場合、value の未初期化結果値は次のようになります。
valueが不定値でもある場合、不定値。
|
(C++26以降) |
評価evalが未初期化対応型 (uninitialized-friendly type) の不定またはエラー(C++26以降)値 value を生成する場合、以下のケースで動作は適切に定義されます。
-
evalは以下の式およびオペランドのいずれかの評価である場合:
- この場合、操作の結果は
valueの未初期化結果値です。
-
evalは、左オペランドが未初期化対応型のlvalueである単純代入演算子の右オペランドの評価である場合。
- この場合、左オペランドによって参照されるオブジェクトの値は、
valueの未初期化結果値に置き換えられます。
-
evalは、未初期化対応型のオブジェクトを初期化する際の初期化式の評価である場合。
| (C++17以降) |
- この場合、そのオブジェクトは
valueの未初期化結果値に初期化されます。
未初期化対応型の不定値を変換すると、不定値が生成されます。
|
未初期化対応型のエラー値を変換すると、エラー値が生成され、変換の結果は変換されたオペランドの値となります。 |
(C++26以降) |
// Case 1: Uninitialized objects with dynamic storage duration // All C++ versions: indeterminate value + undefined behavior int f(bool b) { unsigned char* c = new unsigned char; unsigned char d = *c; // OK, “d” has an indeterminate value int e = d; // undefined behavior return b ? d : 0; // undefined behavior if “b” is true } // Case 2: Uninitialized objects with automatic storage duration // until C++26: indeterminate value + undefined behavior // since C++26: erroneous value + erroneous behavior int g(bool b) { unsigned char c; // “c” has an indeterminate/erroneous value unsigned char d = c; // no undefined/erroneous behavior, // but “d” has an indeterminate/erroneous value assert(c == d); // holds, but both integral promotions have // undefined/erroneous behavior int e = d; // undefined/erroneous behavior return b ? d : 0; // undefined/erroneous behavior if “b” is true } // Same as case 2 void h() { int d1, d2; // “d1” and “d2” have indeterminate/erroneous values int e1 = d1; // undefined/erroneous behavior int e2 = d1; // undefined/erroneous behavior assert(e1 == e2); // holds assert(e1 == d1); // holds, undefined/erroneous behavior assert(e2 == d1); // holds, undefined/erroneous behavior // no undefined/erroneous behavior, // but “d2” has an indeterminate/erroneous value std::memcpy(&d2, &d1, sizeof(int)); assert(e1 == d2); // holds, undefined/erroneous behavior assert(e2 == d2); // holds, undefined/erroneous behavior }
[編集] 注釈
参照およびconstスカラーオブジェクトはデフォルト初期化できません。
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_constexpr |
201907L |
(C++20) | constexpr関数内の自明なデフォルト初期化とasm-宣言 |
[編集] 例
#include <string> struct T1 { int mem; }; struct T2 { int mem; T2() {} // “mem” is not in the initializer list }; int n; // static non-class, a two-phase initialization is done: // 1) zero-initialization initializes n to zero // 2) default-initialization does nothing, leaving n being zero int main() { [[maybe_unused]] int n; // non-class, the value is indeterminate std::string s; // class, calls default constructor, the value is "" std::string a[2]; // array, default-initializes the elements, the value is {"", ""} // int& r; // Error: a reference // const int n; // Error: a const non-class // const T1 t1; // Error: const class with implicit default constructor [[maybe_unused]] T1 t1; // class, calls implicit default constructor const T2 t2; // const class, calls the user-provided default constructor // t2.mem is default-initialized }
[編集] 欠陥レポート
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 178 | C++98 | 値初期化が存在しなかった; 空の初期化子はデフォルト初期化を呼び出した (ただし new T()もゼロ初期化を実行する) |
空の初期化子は以下を呼び出す 値初期化 |
| CWG 253 | C++98 | constオブジェクトのデフォルト初期化は 暗黙的に宣言されたデフォルトコンストラクタを呼び出すことができなかった |
すべてのサブオブジェクトが初期化されている場合は許可 |
| CWG 616 | C++98 | 任意の未初期化オブジェクトの lvalueからrvalueへの変換は常にUBだった |
不定のunsigned charは許可される |
| CWG 1787 | C++98 | 不定のunsigned charからの読み出しはレジスタにキャッシュされていてもUBだった |
符号ビットにシフトする動作は定義された |