Joachim Pileborgが彼の回答で示しているように、グローバル変数は動的初期化子を持つことができ、C++およびC++/CXで「静的コンストラクター」の形式として使用できます。ラムダ式を使用して、初期化をローカルに保つことができることに注意してください。
int Foo::bar = [](){ return 123; }();
ただし、2つの理由から、可能であれば、これを行わないことをお勧めします。まず、グローバル変数が動的に初期化される順序は、部分的にしか指定されていません。別のソースファイルで定義されている他のグローバル変数に依存する動的初期化子がある場合、問題が発生する可能性があります。
次に、さらに重要なことに、WindowsランタイムコンポーネントはDLLであり、グローバル変数の動的初期化はDLL初期化の一部として発生します。これは、DLLのエントリポイントが呼び出されたときに発生します。MSDNがドキュメントに記載しているようにDllMain
、「DLLエントリポイントで実行できることには重大な制限があります。」インターネットで「DllMain」を検索すると、DLLの初期化中にエキサイティングなことを行うことで発生する可能性のある問題を説明する多くのリソースが見つかります。
特に、別のDLLがロードされる可能性のあることを行うことは禁止されています。これは、一般に、DLLで定義されていないWindowsランタイムタイプは、それらが定義されているDLLがまだロードされていない可能性があるため、直接または間接的に使用できないことを意味します。動的初期化中に行われたエキゾチックな作業によって引き起こされたデッドロックに起因するいくつかのハングをデバッグしました。
したがって、別の方法として、グローバル変数を関数にカプセル化します...
class Foo {
public:
static int bar() {
static int value = [](){ return 123; }();
return value;
}
};
...そしてFoo::bar()
の代わりに使用しFoo::bar
ます。ブロックスコープの静的変数は、関数が最初に入力されたときに1回初期化されます。Foo::bar
複数のスレッドから使用する場合は、初期化を同期する必要がある場合があることに注意してください。C ++ 11では、初期化がスレッドセーフである必要がありますが、Visual C ++はまだ(Visual C ++ 2012の時点で)C++11のこの機能をサポートしていません。