2016-04-14 28 views
0

これについて多くの質問がありましたが、この特定のユースケースのコードをコンパイルする方法についての説明はありません。私は次のコマンドを実行します:g++ main.cpp c.cpp testobj.cpp -o main、これを実行して私にSegmentation fault (core dumped)を与えます。 mainメソッドのprintステートメントをmain.cppにして、すべてTestObjコードを削除すると機能します。名前空間内のC++グローバル変数

これは、C::testを割り当てる定数ですか?

main.cppに:

#include "c.h" 
#include "testobj.h" 

TestObj testobj; 

int main() { 
    return 0; 
} 

c.h:

#ifndef CONSTANTS 
#define CONSTANTS 

#include <string> 

namespace C { 
    extern std::string test; 
} 
#endif 

c.cpp:

#include "c.h" 

namespace C { 
    std::string test = "test"; 
} 

試験obj.h:

#ifndef TESTOBJ 
#define TESTOBJ 

class TestObj { 
public: 
    TestObj(); 
}; 

#endif 

testobj.cpp:

#include "testobj.h" 
#include <iostream> 
#include "c.h" 

TestObj::TestObj() { 
    std::cout << C::test << std::endl; 
} 

答えて

2

単一translation unit内のグローバル変数の初期化の順序が明確に定義されているが、翻訳単位の順序は、ありません。

main.cppソースファイルのtestobjオブジェクトがC::testオブジェクトの前に初期化されていると、本当に奇妙な動作になります。

グローバル変数を持つ複数の変換単位がある場合、それらの間の初期化順序に依存することはできません。

+0

'TestObj testobj'の宣言を' TestObj * testobj'に変更し、 '* testobj = TestObj()'を実行して初期化を 'main()'メソッドに移動しますか? – martijnn2008

+0

@ martijnn2008はい、安全なポインタの使用を検討している場合。 :) 'main'関数は、すべてのグローバル変数が初期化された後に常に呼び出されます。 –

1

これは、グローバルな静的変数の初期化順序が原因です。定義されておらず、static initialization order fiascoとして知られています。 TestObj::TestObj(C::testを使用している場合 - まだ構築されていません。

それを解決するための一般的な方法は、関数のローカルスタティック変数にグローバル静的変数を移動させることである、すなわち:

const std::string getTestString() { 
    static std::string test = "test"; 
    return test; 
} 

今、あなたはgetTestString()テスト変数が構築され、それが行われます呼び出すとき正確に1回。また、関数内の静的変数のC++ 11の初期化はスレッドセーフであることが保証されています。

+0

さらに、std :: coutを静的変数のコンストラクタで使用すると安全ではありません。なぜならstd :: cout自体は静的変数であり、初期化にも依存しているからです。 –

+0

@IgorSemenov私はそれについて考えていませんでした.C++ 11は修正されているように見えますから - http://stackoverflow.com/questions/8784892/is-stdcout-guaranteed-to-be-initialized – marcinj

関連する問題