Destructorに副作用があり、オブジェクトに別の静的オブジェクトのデストラクタからアクセスされる場合、静的非向性化を行う方法は?
-
01-10-2019 - |
質問
で説明されている静的初期化の大失敗を避けるためのシンプルでよく知られているパターンがあります C ++ FAQ Liteのセクション10.13.
この標準パターンでは、構築されたオブジェクトが破壊されないというトレードオフがあります(破壊者に重要な副作用がない場合、これは問題ではありません)または静的オブジェクトに別の静的オブジェクトのデストラクタから安全にアクセスできないということです。 (見る C ++ FAQ Liteのセクション10.14).
だから私の質問は、静的オブジェクトの破壊者が最終的に発生しなければならない重要な副作用を持っている場合、静的de Initialization Fiascoをどのように回避するのですか と 静的オブジェクトには、別の静的オブジェクトのデストラクタがアクセスする必要がありますか?
(注:FAQライトは、この質問はFAQ 16.17で回答されています。 C ++ FAQ:よくある質問 M. ClineとG. Lomowによる。私はこの本にアクセスできないので、代わりにこの質問をします。)
解決
グローバルオブジェクトのような関数静的オブジェクトは、それらが作成されていると仮定して破壊されることが保証されています。
破壊の順序は、創造の逆です。
したがって、オブジェクトが破壊中に別のオブジェクトに依存している場合、それがまだ利用可能であることを保証する必要があります。創造の順序が正しく行われることを確認することで、破壊の順序を強制できるため、これは比較的簡単です。
次のリンクはシンゲルトンに関するものですが、同様の状況とその解決策について説明しています。
C ++の静的初期化順序の問題を見つける
FAQ Liteに記載されているように、怠zyな初期化されたグローバルの一般的なケースに外挿して、次のような問題を解決できます。
namespace B
{
class B { ... };
B& getInstance_Bglob;
{
static B instance_Bglob;
return instance_Bglob;;
}
B::~B()
{
A::getInstance_abc().doSomthing();
// The object abc is accessed from the destructor.
// Potential problem.
// You must guarantee that abc is destroyed after this object.
// To gurantee this you must make sure it is constructed first.
// To do this just access the object from the constructor.
}
B::B()
{
A::getInstance_abc();
// abc is now fully constructed.
// This means it was constructed before this object.
// This means it will be destroyed after this object.
// This means it is safe to use from the destructor.
}
}
namespace A
{
class A { ... };
A& getInstance_abc()
{
static A instance_abc;
return instance_abc;
}
}
他のヒント
他のオブジェクトの静的デストラクタが最初に実行される限り、大丈夫です。 「オブジェクトA」の前に他のオブジェクトを構築することにより、これを保証できます。両方のオブジェクトが同じコンピレーションユニットで宣言されている限り、それらはソースに表示される順序で初期化され、反対の順序で破壊されます。
これをコンピレーションユニットで発生させる必要がある場合は、運が悪いです。ランタイムで動的に作成し、静的にするのではなく、メインの終わりにそれらを破壊することです。
ちょっとしたハックですが、de初期化の順序を追跡するためにいくつかの静的なブールを追加し、最後に終わるオブジェクトが所有者でなくてもクリーンアップを行います。