値初期化
From cppreference.com
これは、空の初期化子でオブジェクトが構築されたときに実行される初期化です。
目次 |
[編集] 構文
T () |
(1) | ||||||||
new T () |
(2) | ||||||||
Class::Class(...) : member () { ... } |
(3) | ||||||||
T object {}; |
(4) | (C++11以降) | |||||||
T {} |
(5) | (C++11以降) | |||||||
new T {} |
(6) | (C++11以降) | |||||||
Class::Class(...) : member {} { ... } |
(7) | (C++11以降) | |||||||
[編集] 説明
値初期化は、これらの状況で実行されます。
1,5) 空の丸括弧の初期化子で名前のない一時オブジェクトが作成されるときまたは波括弧(C++11以降)。
3,7) 非静的データメンバーまたは基底クラスが、空の丸括弧のメンバー初期化子で初期化されるときまたは波括弧(C++11以降)。
4) 名前付きオブジェクト(自動、静的、またはスレッドローカル)が波括弧のペアの初期化子で宣言されるとき。
すべてのケースで、空の波括弧 `{}` が使用され、`T` が集約型である場合、値初期化の代わりに集約初期化が実行されます。
|
もし`T`がデフォルトコンストラクタを持たないが、std::initializer_listを取るコンストラクタを持つクラス型である場合、リスト初期化が実行されます。 |
(C++11以降) |
値初期化の効果は以下の通りです。
- もし`T`が(cv修飾されている可能性のある)クラス型の場合
- それ以外の場合、もし`T`が配列型であれば、配列の各要素は値初期化されます。
- それ以外の場合、オブジェクトはゼロ初期化されます。
[編集] 注意
構文 T object(); はオブジェクトを初期化しません。引数なしで`T`を返す関数を宣言します。C++11より前に名前付き変数を値初期化する方法は、T object = T(); でしたが、これは一時オブジェクトを値初期化し、その後オブジェクトをコピー初期化します。ほとんどのコンパイラはこの場合コピーを省略します。
参照は値初期化できません。
関数形式キャストで説明されているように、構文 T() (1) は、`T`が配列型を名前とする場合は禁止されていますが、T{} (5) は許可されています。
すべての標準コンテナ(std::vector、std::listなど)は、単一の`size_type`引数で構築されるとき、または`resize()`の呼び出しによって拡張されるときに、アロケータが`construct`の動作をカスタマイズしない限り、要素を値初期化します。
[編集] 例
このコードを実行
#include <cassert> #include <iostream> #include <string> #include <vector> struct T1 { int mem1; std::string mem2; virtual void foo() {} // make sure T1 is not an aggregate }; // implicit default constructor struct T2 { int mem1; std::string mem2; T2(const T2&) {} // user-provided copy constructor }; // no default constructor struct T3 { int mem1; std::string mem2; T3() {} // user-provided default constructor }; std::string s{}; // class => default-initialization, the value is "" int main() { int n{}; // scalar => zero-initialization, the value is 0 assert(n == 0); double f = double(); // scalar => zero-initialization, the value is 0.0 assert(f == 0.0); int* a = new int[10](); // array => value-initialization of each element assert(a[9] == 0); // the value of each element is 0 T1 t1{}; // class with implicit default constructor => assert(t1.mem1 == 0); // t1.mem1 is zero-initialized, the value is 0 assert(t1.mem2 == ""); // t1.mem2 is default-initialized, the value is "" // T2 t2{}; // error: class with no default constructor T3 t3{}; // class with user-provided default constructor => std::cout << t3.mem1; // t3.mem1 is default-initialized to indeterminate value assert(t3.mem2 == ""); // t3.mem2 is default-initialized, the value is "" std::vector<int> v(3); // value-initialization of each element assert(v[2] == 0); // the value of each element is 0 std::cout << '\n'; delete[] a; }
実行結果の例
42
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 178 | C++98 | 値初期化は存在しませんでした。空の初期化子はデフォルト初期化を呼び出します。 (`new T()`もゼロ初期化を実行しましたが) |
空の初期化子は 値初期化を呼び出します。 |
| CWG 543 | C++98 | ユーザー提供のコンストラクタがないクラスオブジェクトの値初期化は、 各サブオブジェクトの値初期化と同等でした (ユーザー提供のデフォルトコンストラクタを持つメンバーをゼロ初期化する必要はありませんでした) オブジェクト全体を |
ゼロ初期化し、 その後 呼び出します。 デフォルトコンストラクタ |
| CWG 1301 | C++11 | 削除されたデフォルトコンストラクタを持つ共用体の値初期化は、ゼロ初期化につながりました。 CWG 1368 |
現在は デフォルト初期化 |
| ユーザー提供のコンストラクタがあると | C++98 | ゼロ初期化がスキップされました ユーザー提供のコンストラクタのみが |
ゼロ初期化を デフォルトコンストラクタ スキップします。 |
| CWG 1502 | C++11 | ユーザー提供のデフォルトコンストラクタを持たない共用体の値初期化は、 オブジェクトをゼロ初期化するだけでした。デフォルトメンバー初期化子 にもかかわらず |
デフォルト初期化を 実行します。 ゼロ初期化の後 |
| CWG 1507 | C++98 | ユーザー提供のコンストラクタがないクラスオブジェクトの値初期化は、 ユーザー提供のコンストラクタは、 無害なデフォルトコンストラクタの有効性をチェックしませんでした |
無害なコンストラクタの デフォルトコンストラクタ 有効性がチェックされます。 |
| CWG 2820 | C++98 | ゼロ初期化に続くデフォルト初期化は、 非無害なコンストラクタを必要としました。 |
要求されない |
| CWG 2859 | C++98 | クラスオブジェクトの値初期化は、 デフォルト初期化が 実際にユーザー提供のコンストラクタを選択しない場合でも |
ゼロ初期化を含む場合があります。 ゼロ初期化の後 この場合に |