2012-02-01 7 views
5

2つのコンパイル単位(globals.cppstuff.cpp)を持つ共有ライブラリをコンパイルしています。 globals.cppファイルは、stuff.cppで使用されるいくつかのextern変数を初期化します。私が経験している問題は、globals.cppのコードがextern変数に値を代入する機会があった前に、stuff.cppのコードが実行されていることです。たとえば、0の値が使用されています。この問題は、コードをコンパイル/実行するプラットフォームによって異なります。一部のプラットフォームでは動作しません。私のextern変数がまだ初期化されていないのはなぜですか?

これを解決するにはどうすればよいですか?最初にglobals.cppに強制的に実行することはできますか

+3

[static initialization order fiasco] [1]が発生しています。 [1]:http://stackoverflow.com/questions/3035422/static-initialization-order-fiasco – kfmfe04

+0

ありがとう、少なくとも問題を解決します。 – sholsapp

答えて

6

あなたは(一貫性のある方法で)することはできません

しかし、あなたはそれを回避することができます。あなたはまだ、グローバル変数を持って

// If you have a global variable that has to be initial by a constructor 
MyObj globalX; 

// Instead do this 

MyObj& globalX() { static MyObj x; return x;} 

global.cpp。しかし、それが使用されているときに私たちが知っている機能に入れることによって。関数の静的メンバを使用することにより、関数が呼び出された最初のときに初期化されますが、それ以降は呼び出されません。したがって、最初に使用する前に正しく構築されることがわかります。 comp.lang.C++よくある質問から

+0

これは問題を解決しました。 – sholsapp

2
+0

いつものようにFAQは悪いアドバイスをしています。ポインタを使うということは、オブジェクトが一貫して破壊されていないことを意味し、破壊の順序に関する問題の後続の点は間違っているだけです:http:// stackoverflow。com/questions/335369/finding-C-static-initialization-order-problems#335746 –

+0

@LokiAstari:興味深い。それは完全に間違っていますか? FAQは、「a、b、cのコンストラクタがansを使用する場合、実行時システムが静的な初期化解除中にこれらの3つのオブジェクトの最後が破壊された後にansを破棄するため、通常は大丈夫です」と述べています。それを否定するべきではありません。 – jamesdlin

+0

メモリがOSによってクリーンアップされているため、彼は問題ではないとして漏れを解消します。これはちょうど**ばかげて悪い**です。コンストラクタ/デストラクタを持つものであれば、実際にはメモリではありません。これらのオブジェクトが保持しているリソースとそのクリーンアップに関するリソースです。これらのオブジェクトには何かが存在する可能性があります。オブジェクトを変更すると、漏れがコードの正確性に影響しないことを確認するために、意図的にリークするすべての場所をチェックします(Iamはこれらの場所を見つけることさえできないと推測します)。彼のコメントが関連する唯一の時間は、コンストラクタ/デストラクタのないものです。 –

0

を、私はあなたがグローバル変数のインライン初期化を行っているので、あなたがこのbehaviousを見ていると仮定しています明示的な関数呼び出しはありません。例えばglobals.cpp:

// top of source file 

#include "myincludes.h" 

CSomeClass someObject(432); 
int global_x = 42; 
int global_y = InitY(); 
グローバルオブジェクトとグローバル変数の初期化順序のコンストラクタとデストラクタの順序は、ほとんど決定的ではありません。 (私は、ソースファイル内の変数がトップ宣言から最下位に初期化されるが、 "どのソースファイルが最初に来るか"の順序は定義されていないということを、標準のリファレンスページと照らし合わせることなく推測するだろう)。

グローバルオブジェクト(コンストラクタがライブラリ内の関数の前に実行される場所)を持たないようにするか、グローバル変数の初期化順序に依存します。

明示的にライブラリを初期化する機能を持つ方がよい。おそらく、起動時にこの関数を呼び出す必要があるか、ライブラリのエクスポートされた関数が、初期化が検出されなかった後に呼び出す必要があります。その後、グローバルを初期化します。

私のチームでは、 "main"(または "DllMain")より前に実行されるコードは厳密に許可されていません。つまり、グローバルオブジェクトはありません。初期化グローバルへの関数はありません。