Default-initialization
これは、初期化子なしでオブジェクトが構築された際に実行される初期化です。
目次 |
構文
T object
;
|
(1) | ||||||||
new
T
|
(2) | ||||||||
説明
デフォルト初期化は以下の3つの状況で実行されます:
デフォルト初期化の効果は以下の通りです:
-
Tが(CV修飾の可能性がある) 非POD (C++11まで) クラス型の場合、コンストラクタが考慮され、 オーバーロード解決 が空の引数リストに対して実行される。選択されたコンストラクタ( デフォルトコンストラクタ の一つ)が呼び出され、新しいオブジェクトの初期値が提供される; -
Tが配列型の場合、配列の各要素がデフォルト初期化される; - それ以外の場合、初期化は行われない( 注記 を参照)。
|
初期化子が使用されない場合、自動記憶域期間を持つ(おそらくcv修飾された)非PODクラス型(またはその配列)のみがデフォルト初期化されると見なされていました。動的記憶域期間を持つスカラー型とPOD型は初期化されていないと見なされていました(C++11以降、この状況はデフォルト初期化の一形態として再分類されました)。 |
(until C++11) |
|
(C++11まで) |
|
(C++11以降) |
T
の各
潜在的に構築される
基底クラスがconst-default-constructibleである。
不定値および誤った値
|
自動または動的ストレージ期間を持つオブジェクトのストレージが取得されると、そのオブジェクトは 不定値 を持つ。 オブジェクトに対して初期化が行われない場合、そのオブジェクトは値が置き換えられるまで不定値を保持する。 |
(C++26まで) |
|
自動または動的ストレージ期間を持つオブジェクトのストレージが取得されると、オブジェクトのストレージを構成するバイトは以下の初期値を持つ:
オブジェクト( 部分オブジェクト を含む)に対して初期化が行われない場合、そのようなバイトは値が置き換えられるまで初期値を保持する。
|
(C++26以降) |
評価が不定値を生成する場合、その動作は undefined です。
|
評価が誤った値を生成する場合、その動作は 誤った動作 となります。 |
(C++26以降) |
特殊ケース
以下の型は uninitialized-friendly です:
| (C++17以降) |
- unsigned char
- char 、その基盤となる型が unsigned char である場合
不定の または誤った (C++26以降) 値 value が与えられたとき、 value の 未初期化結果値 は以下の通りです:
- 不定値、もし value も不定値である場合。
|
(C++26以降) |
評価 eval が初期化未対応フレンドリー型の不定 または誤った (C++26以降) 値 value を生成する場合、以下のケースでは動作は明確に定義されます:
- eval は以下の式とオペランドのいずれかの評価です:
-
- 条件式の第2または第3オペランド。
- コンマ式の右オペランド。
-
整数変換、明示的キャスト、または初期化不要フレンドリー型への
static_castのオペランド。 - 破棄値式。
- この場合、演算の結果は value の未初期化結果値となります。
- eval は、左オペランドが初期化フレンドリー型の左辺値である 単純代入演算子 の右オペランドの評価です。
- この場合、左オペランドによって参照されるオブジェクトの値は、 value の未初期化結果値によって置き換えられます。
- eval は、初期化されていないフレンドリー型のオブジェクトを初期化する際の初期化式の評価です。
| (C++17以降) |
- この場合、そのオブジェクトは value の未初期化結果値で初期化されます。
初期化に寛容な型の不定値の変換は、不定値を生成します。
|
未初期化フレンドリー型の不正な値を変換すると不正な値が生成され、変換の結果は変換されたオペランドの値となります。 |
(C++26以降) |
// ケース1: 動的記憶域期間を持つ未初期化オブジェクト // 全C++バージョン: 不定値 + 未定義動作 int f(bool b) { unsigned char* c = new unsigned char; unsigned char d = *c; // OK、「d」は不定値を持つ int e = d; // 未定義動作 return b ? d : 0; // 「b」がtrueの場合、未定義動作 } // ケース2: 自動記憶域期間を持つ未初期化オブジェクト // C++26まで: 不定値 + 未定義動作 // C++26以降: 誤った値 + 誤った動作 int g(bool b) { unsigned char c; // 「c」は不定値/誤った値を持つ unsigned char d = c; // 未定義動作/誤った動作なし、 // ただし「d」は不定値/誤った値を持つ assert(c == d); // 成立するが、両方の整数昇格は // 未定義動作/誤った動作を持つ int e = d; // 未定義動作/誤った動作 return b ? d : 0; // 「b」がtrueの場合、未定義動作/誤った動作 } // ケース2と同じ void h() { int d1, d2; // 「d1」と「d2」は不定値/誤った値を持つ int e1 = d1; // 未定義動作/誤った動作 int e2 = d1; // 未定義動作/誤った動作 assert(e1 == e2); // 成立 assert(e1 == d1); // 成立、未定義動作/誤った動作 assert(e2 == d1); // 成立、未定義動作/誤った動作 // 未定義動作/誤った動作なし、 // ただし「d2」は不定値/誤った値を持つ std::memcpy(&d2, &d1, sizeof(int)); assert(e1 == d2); // 成立、未定義動作/誤った動作 assert(e2 == d2); // 成立、未定義動作/誤った動作 }
注記
参照とconstスカラーオブジェクトはデフォルト初期化できません。
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_constexpr
|
201907L
|
(C++20) | constexpr関数での自明なデフォルト初期化と asm宣言 |
例
#include <string> struct T1 { int mem; }; struct T2 { int mem; T2() {} // 「mem」は初期化子リストに含まれていない }; int n; // 静的非クラス型、二段階初期化が行われる: // 1) ゼロ初期化によりnはゼロに初期化される // 2) デフォルト初期化は何もせず、nはゼロのまま int main() { [[maybe_unused]] int n; // 非クラス型、値は不定 std::string s; // クラス型、デフォルトコンストラクタを呼び出し、値は"" std::string a[2]; // 配列、要素をデフォルト初期化し、値は{"", ""} // int& r; // エラー:参照 // const int n; // エラー:const非クラス型 // const T1 t1; // エラー:暗黙のデフォルトコンストラクタを持つconstクラス [[maybe_unused]] T1 t1; // クラス型、暗黙のデフォルトコンストラクタを呼び出す const T2 t2; // constクラス型、ユーザー提供のデフォルトコンストラクタを呼び出す // t2.memはデフォルト初期化される }
欠陥報告
以下の動作変更欠陥報告書は、以前に公開された C++ 標準に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| CWG 178 | C++98 |
値初期化が存在しなかった;
空の初期化子はデフォルト初期化を呼び出した (ただし new T ( ) はゼロ初期化も実行する) |
空の初期化子は
値初期化を呼び出す |
| CWG 253 | C++98 |
constオブジェクトのデフォルト初期化では
暗黙的に宣言されたデフォルトコンストラクタを呼び出せなかった |
すべてのサブオブジェクトが初期化される場合は許可される |
| CWG 616 | C++98 |
未初期化オブジェクトの左辺値から右辺値への変換は
常に未定義動作だった |
不定値の unsigned char は許可される |
| CWG 1787 | C++98 |
不定値の
unsigned
char
からの読み取りが
レジスタにキャッシュされる場合は未定義動作だった |
明確に定義された動作に変更 |