Value-initialization
これは、空の初期化子でオブジェクトが構築された際に実行される初期化です。
目次 |
構文
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以降) | |||||||
説明
値初期化は以下の状況で実行されます:
すべての場合において、空の中括弧のペア
{}
が使用され、かつ
T
が集成体型である場合、
aggregate initialization
が値初期化の代わりに実行されます。
|
|
(C++11以降) |
値初期化の効果は以下の通りです:
-
Tが(CV修飾された可能性のある)クラス型の場合:
-
-
Tのデフォルト初期化が コンストラクタ を選択し、かつそのコンストラクタが user-declared (C++11まで) user-provided (C++11以降) でない場合、オブジェクトはまず zero-initialized される。 - いずれの場合でも、オブジェクトは default-initialized される。
-
-
それ以外の場合、
Tが配列型であれば、配列の各要素は値初期化されます。 - それ以外の場合、オブジェクトはゼロ初期化されます。
注記
構文
T object
(
)
;
はオブジェクトを初期化せず、引数を取らずに
T
を返す関数を宣言する。C++11以前で名前付き変数を値初期化する方法は
T object
=
T
(
)
;
であり、これは一時オブジェクトを値初期化してからオブジェクトをコピー初期化する:ほとんどのコンパイラはこの場合
コピーを最適化で除去する
。
`タグ内の`T`は翻訳対象外
- C++特有の用語(value-initialize, copy-initialize, copy elisionなど)は専門用語としてそのまま使用
- 構文例は完全に保持
- 技術文書としての正確性と専門性を維持
参照は値初期化できません。
function-style cast
で説明されているように、
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() {} // T1が集成体でないことを保証 }; // 暗黙のデフォルトコンストラクタ struct T2 { int mem1; std::string mem2; T2(const T2&) {} // ユーザー提供のコピーコンストラクタ }; // デフォルトコンストラクタなし struct T3 { int mem1; std::string mem2; T3() {} // ユーザー提供のデフォルトコンストラクタ }; std::string s{}; // クラス型 => デフォルト初期化、値は"" int main() { int n{}; // スカラー型 => ゼロ初期化、値は0 assert(n == 0); double f = double(); // スカラー型 => ゼロ初期化、値は0.0 assert(f == 0.0); int* a = new int[10](); // 配列 => 各要素の値初期化 assert(a[9] == 0); // 各要素の値は0 T1 t1{}; // 暗黙のデフォルトコンストラクタを持つクラス => assert(t1.mem1 == 0); // t1.mem1はゼロ初期化され、値は0 assert(t1.mem2 == ""); // t1.mem2はデフォルト初期化され、値は"" // T2 t2{}; // エラー: デフォルトコンストラクタのないクラス T3 t3{}; // ユーザー提供のデフォルトコンストラクタを持つクラス => std::cout << t3.mem1; // t3.mem1はデフォルト初期化され不定値 assert(t3.mem2 == ""); // t3.mem2はデフォルト初期化され、値は"" std::vector<int> v(3); // 各要素の値初期化 assert(v[2] == 0); // 各要素の値は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 |
クラスオブジェクトの値初期化は、デフォルト初期化が
実際にユーザー提供コンストラクタを選択しない場合でも ゼロ初期化を含む可能性があった |
この場合
ゼロ初期化は 行われない |