初期化
変数の初期化は構築時にその初期値を提供します。
初期値は宣言子または new 式の初期化子節で提供することができます。 また関数呼び出しでも行われます。 関数の引数および関数の戻り値も初期化されます。
それぞれの宣言子に対して、以下のいずれかの初期化子を指定できます。
( expression-list) | (1) | ||||||||
= expression | (2) | ||||||||
{ initializer-list} | (3) | ||||||||
文脈によって、初期化子は以下を発生させます。
- 値初期化、例えば std::string s{};
- 直接初期化、例えば std::string s("hello");
- コピー初期化、例えば std::string s ="hello";
- リスト初期化、例えば std::string s{'a', 'b', 'c'};
- 集成体初期化、例えば char a[3]={'a', 'b'};
- 参照初期化、例えば char& c = a[0];
初期化子が提供されない場合は、デフォルト初期化のルールが適用されます。
目次 |
[編集]非ローカル変数
静的記憶域期間を持つすべての非ローカル変数は、 main 関数の実行が始まる前に、プログラムのスタートアップの一部として初期化されます (遅延されている場合は除きます (後述))。 スレッドローカル記憶域期間を持つすべての非ローカル変数は、スレッドの関数の実行の開始に対して先行配列される、スレッド起動処理の一部として初期化されます。 これらの変数の記憶域クラスについて、初期化は2つの別々のステージで発生します。
[編集]静的初期化
.bss
セグメントに配置されます。 これはディスク上のスペースを占めず、プログラムのロード時に OS によってゼロ初期化されます。[編集]動的初期化
すべての静的初期化の完了後、非ローカル変数の動的初期化が以下の状況で発生します。
2)部分的順序付き動的初期化。 暗黙にまたは明示的に実体化された特殊化でないすべてのインライン変数に適用されます。 部分的順序付きの V がすべての翻訳単位において順序付きまたは部分的順序付きの W より前の場合、 V の初期化は W の初期化に対して先行配列されます (または、プログラムがスレッドを開始する場合は先行発生します)。 | (C++17以上) |
静的およびスレッド記憶域期間を持つ非ローカル変数の初期化が例外によって終了した場合は、 std::terminate が呼ばれます。
[編集]早期動的初期化
以下の条件がどちらも真の場合、コンパイラは静的初期化の一部として (本質的にコンパイル時に) 動的初期化される変数を初期化することが許されています。
上記のルールのため、何らかのオブジェクト o1
の初期化が名前空間スコープのオブジェクト o2
を参照し、 o2
が動的初期化を要求するかもしれないけれども、同じ翻訳単位内で後に定義されている場合、使用される o2
の値が、完全に初期化された o2
の値になる (コンパイラが o2
の初期化をコンパイル時に昇格したため) か、ゼロ初期化されただけの o2
の値になるかは、未規定です。
inlinedouble fd(){return1.0;}externdouble d1;double d2 = d1;// 未規定。// d1 が動的初期化される場合は 0.0 に動的初期化され、// d1 が静的初期化される場合は 1.0 に動的初期化され、// または 0.0 に静的初期化されます (両方の変数が動的初期化されれば// その値になるであろうから)。double d1 = fd();// 1.0 に静的または動的初期化されます。
[編集]遅延動的初期化
動的初期化が main 関数 (静的変数の場合) またはスレッドの初期関数 (スレッドローカル変数の場合) の最初の文に対して先行発生するか、遅延されて後続発生するかは、処理系定義です。
非インライン(C++17以上)変数の初期化が遅延されて main 関数またはスレッド関数の最初の文に対して後続発生する場合、それは変数が初期化されたのと同じ翻訳単位内で定義された静的またはスレッドローカル記憶域期間を持つ任意の変数の最初の ODR 使用に対して先行発生します。 ある翻訳単位内から ODR 使用される変数や関数がない場合、その翻訳単位内で定義される非ローカル変数は初期化されることがないかもしれません (これはオンデマンドな動的ライブラリの動作をモデル化します)。 しかし、その翻訳単位から何かが ODR 使用される限り、初期化または破棄が副作用を持つすべての非ローカル変数は、それらがプログラム内で使用されなくても、初期化されます。
インライン変数の初期化が遅延される場合、それはその特定の変数の最初の ODR 使用に対して先行発生します。 | (C++17以上) |
// ー ファイル1 ー#include "a.h"#include "b.h" B b; A::A(){ b.Use();} // ー ファイル2 ー#include "a.h" A a; // ー ファイル3 ー#include "a.h"#include "b.h"extern A a;extern B b; int main(){ a.Use(); b.Use();} // main に入る前に a が初期化された場合、 A::A() がそれを使用する時点では// b はまだ初期化されていない可能性があります (動的初期化は翻訳単位間では不定に配列されるため)。 // main の最初の文 (ファイル1で定義された関数を ODR 使用し、動的初期化の実行を強制させます) の後の// いずれかの時点で a が初期化された場合、 b は A::A で使用される前に初期化されます。
[編集]静的ローカル変数
ローカルな (つまりブロックスコープの) 静的およびスレッドローカル変数の初期化については、静的ローカル変数を参照してください。
[編集]クラスメンバ
非静的データメンバはメンバ初期化子リストまたは デフォルトメンバ初期化子で初期化できます。
[編集]ノート
非ローカル変数の破棄の順序は std::exit で説明されます。
[編集]欠陥報告
以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。
DR | 適用先 | 発行時の動作 | 正しい動作 |
---|---|---|---|
CWG 2026 | C++14 | zero-init was specified to always occur first, even before constant-init | no zero-init if constant init applies |
[編集]関連項目
初期化 の C言語リファレンス |