名前空間
変種
操作

初期化

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (非推奨)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

変数の初期化は構築時にその初期値を提供します。

初期値は宣言子または new 式の初期化子節で提供することができます。 また関数呼び出しでも行われます。 関数の引数および関数の戻り値も初期化されます。

それぞれの宣言子に対して、以下のいずれかの初期化子を指定できます。

( expression-list ) (1)
= expression (2)
{ initializer-list } (3)
1) 括弧に囲まれた braced-init-list および任意の式のコンマ区切りのリスト
2) 等号に続く式
3) braced-init-list (空かもしれない、他の braced-init-list および式のコンマ区切りのリスト)

文脈に依存して、初期化子は以下を起動することがあります。

初期化子が提供されない場合は、デフォルト初期化のルールが適用されます。

目次

[編集] 非ローカル変数

静的記憶域期間を持つすべての非ローカル変数は、 main 関数の実行が始まる前に、プログラムのスタートアップの一部として初期化されます (遅延されている場合は除きます (後述))。 スレッドローカル記憶域期間をもつすべての変数は、スレッドの関数の実行の開始に対して先行配列される、スレッド起動処理の一部として初期化されます。 これらの変数の記憶域クラスについて、初期化は2つの別々のステージで発生します。

[編集] 静的初期化

1) 可能であれば、まず定数初期化が行われます (それらの状況の一覧については定数初期化を参照してください)。 実際には、定数初期化は、通常、コンパイル時に行われ、事前計算されたオブジェクト表現がプログラムイメージの一部として格納されます。 コンパイラは、それを行わない場合でも、いかなる動的初期化も発生する前にこの初期化が行われることを保証する必要があります。
2) それ以外のすべての非ローカル静的変数およびスレッドローカル変数については、ゼロ初期化が行われます。 実際には、ゼロ初期化される変数は、プログラムイメージの .bss セグメントに配置されます。 これはディスク上のスペースを占めず、プログラムのロード時に OS によってゼロ初期化されます。

[編集] 動的初期化

すべての静的初期化の完了後、非ローカル変数の動的初期化が以下の状況で発生します。

1) 順序なし動的初期化。 (静的またはスレッドローカルな) 明示的に特殊化されていないクラステンプレートの静的データメンバおよび変数テンプレート (C++14およびそれ以降)にのみ適用されます。 そのような静的変数の初期化は他のすべての動的初期化に対して不定に配列されます。 ただし変数が初期化される前にプログラムがスレッドを開始した場合、その初期化は配列されません。 (C++17およびそれ以降) そのようなスレッドローカル変数の初期化は、他のすべての動的初期化に対して配列されません。
2) 部分的順序付き動的初期化。 暗黙にまたは明示的に実体化された特殊化でないすべてのインライン変数に適用されます。 部分的順序付きの V がすべての翻訳単位において順序付きまたは部分的順序付きの W より前の場合、 V の初期化は W の初期化に対して先行配列されます (または、プログラムがスレッドを開始する場合は先行発生します)。
(C++17およびそれ以降)
3) 順序付き動的初期化。 他のすべての非ローカル変数に適用されます。 単一の翻訳単位内においては、これらの変数の初期化は必ずソースコード中に定義が現れた通りの順序に配列されます。 異なる翻訳単位内の静的変数の初期化は不定に配列されます。 異なる翻訳単位内のスレッドローカル変数の初期化は配列されません。

静的およびスレッド記憶域期間を持つ非ローカル変数の初期化が例外によって終了した場合は、 std::terminate が呼ばれます。

[編集] 早期動的初期化

以下の条件がどちらも真の場合、コンパイラは静的初期化の一部として (本質的にコンパイル時に) 動的初期化される変数を初期化することが許されています。

1) その初期化の動的バージョンが、その初期化に先行する名前空間スコープの他のいかなるオブジェクトの値も変更しない。
2) その初期化の静的バージョンが、もし静的に初期化されることが要求されないすべての変数が動的に初期化されたならばその動的初期化によって生成されたであろう値と同じ値を、その初期化された変数に生成する。

上記のルールのため、何らかのオブジェクト o1 の初期化が名前空間スコープのオブジェクト o2 を参照し、 o2 が動的初期化を要求するかもしれないけれども、同じ翻訳単位内で後に定義されている場合、使用される o2 の値が、完全に初期化された o2 の値になる (コンパイラが o2 の初期化をコンパイル時に昇格したため) か、ゼロ初期化されただけの o2 の値になるかは、未規定です。

inline double fd() { return 1.0; }
extern double d1;
double d2 = d1;   // unspecified:
                  // dynamically initialized to 0.0 if d1 is dynamically initialized, or
                  // dynamically initialized to 1.0 if d1 is statically initialized, or
                  // statically initialized to 0.0 (because that would be its value
                  // if both variables were dynamically initialized)
double d1 = fd(); // may be initialized statically or dynamically to 1.0

[編集] 遅延動的初期化

動的初期化が main 関数 (静的変数の場合) またはスレッドの初期関数 (スレッドローカル変数の場合) の最初の文に対して先行発生するか、遅延されて後続発生するかは、処理系定義です。

非インライン (C++17およびそれ以降)変数の初期化が遅延されて main 関数またはスレッド関数の最初の文に対して後続発生する場合、それは変数が初期化されたのと同じ翻訳単位内で定義された静的またはスレッドローカル記憶域期間を持つ任意の変数の最初の ODR 使用に対して先行発生します。 ある翻訳単位内から ODR 使用される変数や関数がない場合、その翻訳単位内で定義される非ローカル変数は初期化されることがないかもしれません (これはオンデマンドな動的ライブラリの動作をモデル化します)。 しかし、その翻訳単位から何かが ODR 使用される限り、初期化または破棄が副作用を持つすべての非ローカル変数は、それらがプログラム内で使用されなくても、初期化されます。

インライン変数の初期化が遅延される場合、それはその特定の変数の最初の ODR 使用に対して先行発生します。

(C++17およびそれ以降)
// - File 1 -
#include "a.h"
#include "b.h"
B b;
A::A(){ b.Use(); }
 
// - File 2 -
#include "a.h"
A a;
 
// - File 3 -
#include "a.h"
#include "b.h"
extern A a;
extern B b;
 
int main() {
  a.Use();
  b.Use();
}
 
// if a is initialized before main is entered, b may still be uninitialized
// at the point where A::A() uses it (because dynamic init is indeterminately sequenced
// across translation units)
 
// If a is initialized at some point after the first statement of main (which odr-uses
// a function defined in File 1, forcing its dynamic initialization to run),
// then b will be initialized prior to its use in 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

[編集] 関連項目