C ++関数の静的変数の寿命はどれくらいですか?
質問
変数が関数のスコープで static
として宣言されている場合、変数は一度だけ初期化され、関数呼び出し間で値を保持します。その寿命は正確に何ですか?コンストラクタとデストラクタはいつ呼び出されますか?
void foo()
{
static string plonk = "When will I die?";
}
解決
関数 static
変数の有効期間は、プログラムフローが宣言を最初に検出した [0] から始まり、プログラムの終了時に終了します。これは、実際に構築された場合にのみ、それを破壊するためにランタイムが何らかのブックキーピングを実行する必要があることを意味します。
さらに、標準では静的オブジェクトのデストラクタは構築完了と逆の順序で実行する必要があるとされているため [1] 、構築の順序は特定のプログラム実行に依存する場合があります、建設の順序を考慮する必要があります。
例
struct emitter {
string str;
emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
~emitter() { cout << "Destroyed " << str << endl; }
};
void foo(bool skip_first)
{
if (!skip_first)
static emitter a("in if");
static emitter b("in foo");
}
int main(int argc, char*[])
{
foo(argc != 2);
if (argc == 3)
foo(false);
}
出力:
C:&gt; sample.exe
foo
で作成 fooで破壊されましたC:&gt; sample.exe 1
if
で作成 foo
で作成 foo
で破壊されました 破壊された場合C:&gt; sample.exe 1 2
foo
で作成 if
で作成 if
で破壊されました fooで破壊されました
[0]
C ++ 98 [2] はマルチスレッドへの参照を持たないため、マルチスレッドでの動作はスレッド環境は指定されておらず、 Roddy の言及。
[1]
C ++ 98 セクション 3.6.3.1
[basic.start.term]
[2]
C ++ 11の静的変数はスレッドセーフな方法で初期化され、これは Magic Statics 。
他のヒント
Mottiは注文について正しいですが、他にも考慮すべきことがいくつかあります:
コンパイラは通常、ローカルスタティックがすでに初期化されているかどうかを示すために非表示フラグ変数を使用し、このフラグは関数へのすべてのエントリでチェックされます。明らかにこれは小さなパフォーマンスヒットですが、より重要なことは、このフラグがスレッドセーフであることが保証されていないことです。
上記のようにローカルスタティックがあり、 foo
が複数のスレッドから呼び出された場合、 plonk
が誤ってまたは複数回初期化される競合状態が発生する可能性があります。また、この場合、 plonk
は、それを構築したスレッドとは異なるスレッドによって破壊される可能性があります。
規格が言っていることにもかかわらず、私はローカルの静的破壊の実際の順序に非常に警戒します。なぜなら、破壊された後でも静的がまだ有効であることに無意識に依存する可能性があり、これを追跡するのは本当に難しいからですダウン。
既存の説明は、6.7にある標準の実際のルールなしでは実際には完全ではありません。
他の初期化が行われる前に、静的ストレージ期間またはスレッドストレージ期間を持つすべてのブロックスコープ変数のゼロ初期化が実行されます。該当する場合、ブロックが最初に入力される前に、静的ストレージ期間を使用したブロックスコープエンティティの定数初期化が実行されます。実装は、名前空間のスコープで静的またはスレッドの保存期間で変数を静的に初期化できるのと同じ条件下で、静的またはスレッドの保存期間で他のブロックスコープ変数の初期初期化を実行できます。そうでない場合、そのような変数は、コントロールがその宣言を最初に通過するときに初期化されます。このような変数は、初期化が完了すると初期化されたと見なされます。例外をスローして初期化が終了した場合、初期化 は完全ではないため、次回コントロールが宣言に入るときに再試行されます。変数の初期化中に制御が同時に宣言に入る場合、同時実行は初期化の完了を待機します。変数の初期化中にコントロールが宣言を再帰的に再入力した場合、動作は未定義です。
FWIW、Codegear C ++ Builderは標準に従って期待される順序で破壊されません。
C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if
...これは、破壊順序に依存しないもう1つの理由です!
静的変数は、プログラムの実行が開始すると有効になり、プログラムの実行が終了するまで使用可能です。
静的変数は、メモリのデータセグメントで作成されます。