静的オブジェクトが破棄される順序を制御できますか? 希望の注文を強制する方法はありますか? たとえば、特定のオブジェクトを最後に、または少なくとも別の静的オブジェクトの後に破棄することを何らかの方法で指定するには?
9 に答える
静的オブジェクトは、構築と逆の順序で破棄されます。そして、構築の順序を制御するのは非常に困難です。確実なのは、同じコンパイル単位で定義された 2 つのオブジェクトが定義順に構築されるということだけです。それ以外は多かれ少なかれランダムです。
これに対する他の答えは、それはできないと主張しています。仕様によると、彼らは正しいですが、それを可能にするトリックがあります。
次のように、通常静的変数を作成する他のすべてのものを含むクラスまたは構造体の単一の静的変数のみを作成します。
class StaticVariables {
public:
StaticVariables(): pvar1(new Var1Type), pvar2(new Var2Type) { };
~StaticVariables();
Var1Type *pvar1;
Var2Type *pvar2;
};
static StaticVariables svars;
のコンストラクタとデストラクタで、必要な順序で変数を作成できます。さらに重要なことに、必要な順序で変数を破棄StaticVariables
できます。これを完全に透過的にするために、次のように変数への静的参照も作成できます。
static Var1Type &var1(*svars.var1);
出来上がり-完全なコントロール。:-) とはいえ、これは余分な作業であり、通常は不要です。しかし、必要な場合は、それについて知っておくと非常に便利です。
短い答え: 一般的に、いいえ。
少し長い答え: 単一の翻訳単位内のグローバルな静的オブジェクトの場合、初期化順序は上から下であり、破棄順序はまったく逆です。複数の翻訳単位間の順序は定義されていません。
本当に特定の注文が必要な場合は、自分で作成する必要があります。
標準の C++ でそれを行う方法はありませんが、特定のコンパイラの内部構造に関する実用的な知識があれば、おそらく実現できます。
Visual C++ では、静的 init 関数へのポインターは.CRT$XI
セグメント (C タイプの static init の場合) または.CRT$XC
セグメント (C++ タイプの static init の場合) にあります。リンカーはすべての宣言を収集し、アルファベット順にマージします。を使用して適切なセグメントでオブジェクトを宣言することにより、静的初期化が発生する順序を制御できます。
#pragma init_seg
たとえば、ファイル A のオブジェクトをファイル B のオブジェクトの前に作成する場合:
ファイル A.cpp:
#pragma init_seg(".CRT$XCB")
class A{}A;
ファイル B.cpp:
#pragma init_seg(".CRT$XCC")
class B{}B;
.CRT$XCB
の前にマージされ.CRT$XCC
ます。CRT が静的 init 関数ポインターを反復処理すると、ファイル B の前にファイル A が検出されます。
Watcom では、セグメントは XI であり、#pragma initialize のバリエーションで構造を制御できます。
#pragma initialize before library
#pragma initialize after library
#pragma initialize before user
...詳細についてはドキュメントを参照してください
前に変数を初期化する必要がありますmain
か?
そうでない場合は、単純なイディオムを使用して、構築と破棄の順序を実際に簡単に制御できます。こちらを参照してください。
#include <cassert>
class single {
static single* instance;
public:
static single& get_instance() {
assert(instance != 0);
return *instance;
}
single()
// : normal constructor here
{
assert(instance == 0);
instance = this;
}
~single() {
// normal destructor here
instance = 0;
}
};
single* single::instance = 0;
int real_main(int argc, char** argv) {
//real program here...
//everywhere you need
single::get_instance();
return 0;
}
int main(int argc, char** argv) {
single a;
// other classes made with the same pattern
// since they are auto variables the order of construction
// and destruction is well defined.
return real_main(argc, argv);
}
実際にクラスの 2 番目のインスタンスを作成しようとすることを止めるわけではありませんが、作成するとアサーションは失敗します。私の経験では、うまくいきます。
いいえ、できません。静的オブジェクトの構築/破棄のもう一方に依存するべきではありません。
シングルトンを使用して、グローバル リソースの構築/破棄の順序を制御できます。