初期化の解決順序:
まず、これは一時的な回避策です。これは、削除しようとしているグローバル変数がありますが、まだ時間がないためです(最終的にはそれらを削除する予定ですよね?:-)
class A
{
public:
// Get the global instance abc
static A& getInstance_abc() // return a reference
{
static A instance_abc;
return instance_abc;
}
};
これにより、最初の使用時に初期化され、アプリケーションの終了時に破棄されることが保証されます。
マルチスレッドの問題:
C ++ 11は、これがスレッドセーフであることを保証します。
§6.7[stmt.dcl]p4
変数の初期化中に制御が宣言に同時に入る場合、同時実行は初期化の完了を待機するものとします。
ただし、C ++ 03は、静的関数オブジェクトの構築がスレッドセーフであることを公式に保証するものではありません。したがって、技術的には、getInstance_XXX()
メソッドはクリティカルセクションで保護する必要があります。明るい面として、gccにはコンパイラの一部として明示的なパッチがあり、スレッドが存在する場合でも、各静的関数オブジェクトが1回だけ初期化されることを保証します。
注意:ロックのコストを回避するために、ダブルチェックのロックパターンを使用しないでください。これはC++03では機能しません。
作成の問題:
作成時は使用前に作成することを保証しますので問題ありません。
破壊の問題:
オブジェクトが破棄された後、オブジェクトにアクセスする際に問題が発生する可能性があります。これは、別のグローバル変数のデストラクタからオブジェクトにアクセスする場合にのみ発生します(グローバルでは、非ローカル静的変数を参照しています)。
解決策は、破壊の順序を強制することを確認することです。
破壊の順序は、構築の順序とは正反対であることを忘れないでください。したがって、デストラクタでオブジェクトにアクセスする場合は、オブジェクトが破棄されていないことを保証する必要があります。これを行うには、呼び出し元のオブジェクトが構築される前に、オブジェクトが完全に構築されていることを保証する必要があります。
class B
{
public:
static B& getInstance_Bglob;
{
static B instance_Bglob;
return instance_Bglob;;
}
~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 guarantee this you must make sure it is constructed first.
// To do this just access the object from the constructor.
}
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.
}
};