後でリンクできるように、初期化についてもいくつかのテキストを書きたいと思います。
まず可能性のリスト。
名前空間静的
- 2 つの初期化方法があります。静的(コンパイル時に発生することを意図) および動的(実行時に発生することを意図) 初期化。
- 静的初期化は、翻訳単位の関係を無視して、動的初期化の前に行われます。
- 動的初期化は翻訳単位で順序付けされますが、静的初期化には特定の順序はありません。同じ翻訳単位の名前空間スコープのオブジェクトは、定義が表示される順序で動的に初期化されます。
- 定数式で初期化される POD 型オブジェクトは、静的に初期化されます。それらの値は、翻訳単位の関係を無視して、任意のオブジェクトの動的初期化によって依存できます。
- 初期化で例外がスローされた場合は、
std::terminate
が呼び出されます。
例:
次のプログラムは印刷しますA(1) A(2)
struct A {
A(int n) { std::printf(" A(%d) ", n); }
};
A a(1);
A b(2);
そして、以下は同じクラスに基づいて出力されますA(2) A(1)
extern A a;
A b(2);
A a(1);
msg
次のように定義されている翻訳単位があるとしましょう。
char const *msg = "abc";
次に、次のように表示されabc
ます。p
動的初期化を受け取ることに注意してください。しかし、静的初期化 (char const*
は POD 型で、"abc"
はアドレス定数式)msg
がその前に行われるため、これは問題なく、msg
正しく初期化されることが保証されています。
extern const char *msg;
struct P { P() { std::printf("%s", msg); } };
P p;
- main の前にオブジェクトの動的な初期化を行う必要はありません。ただし、初期化は、オブジェクトまたはその翻訳単位の関数を最初に使用する前に行う必要があります。これは、動的にロード可能なライブラリーにとって重要です。
クラス静的
- 名前空間の static のように動作します。
- 関数またはその翻訳単位のオブジェクトの最初の使用時にコンパイラがクラス statics を初期化できるかどうかについてのバグ レポートもあります (main の後)。標準の文言では、現在、名前空間スコープ オブジェクトに対してのみこれを許可していますが、クラス スコープ オブジェクトに対してもこれを許可することを意図しているようです。Namespace Scope のオブジェクトを読み取ります。
- テンプレートのメンバーであるクラス static のルールは、それらが使用された場合にのみ初期化されるというものです。それらを使用しないと、初期化されません。いずれの場合も、上記で説明したように初期化が行われることに注意してください。テンプレートのメンバーであるため、初期化が遅れることはありません。
ローカル静的
- ローカル スタティックの場合、特別なルールが発生します。
- 定数式で初期化された POD 型オブジェクトは、それらが定義されているブロックに入る前に初期化されます。
- 他のローカル静的オブジェクトは、制御が定義を最初に通過するときに初期化されます。例外がスローされた場合、初期化は完了したとは見なされません。次回から再度初期化を試みます。
例: 次のプログラムは次のように出力し0 1
ます。
struct C {
C(int n) {
if(n == 0)
throw n;
this->n = n;
}
int n;
};
int f(int n) {
static C c(n);
return c.n;
}
int main() {
try {
f(0);
} catch(int n) {
std::cout << n << " ";
}
f(1); // initializes successfully
std::cout << f(2);
}
上記のすべてのケースで、特定の限定的なケースでは、静的に初期化する必要のない一部のオブジェクトについて、コンパイラーは動的に初期化する代わりに静的に初期化できます。これは難しい問題です。より詳細な例については、この回答を参照してください。
また、破壊の順序は、オブジェクトの構築が完了した正確な順序であることに注意してください。これはよくあることで、一時オブジェクトの破棄を含め、C++ のあらゆる状況で発生します。