2016-04-14 4 views
0

Ich habe eine Menge Fragen zu diesem Thema, aber keine Erklärung, wie Sie den Code für diesen speziellen Anwendungsfall kompilieren. Ich führe den folgenden Befehl: g++ main.cpp c.cpp testobj.cpp -o main, aber das Ausführen gibt mir eine Segmentation fault (core dumped). Wenn ich die print-Anweisung in der main-Methode in main.cpp und alle TestObj Code entfernen, funktioniert es.C++ globale Variable in Namespace

Ist dies der richtige Weg, um die C::test Konstante zuzuordnen?

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"; 
} 

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; 
} 

Antwort

2

Während die Reihenfolge der Initialisierung für globale Variablen innerhalb eines einzelnen translation unit gut definiert ist, ist die Reihenfolge zwischen Übersetzungseinheiten nicht .

Wenn also das testobj Objekt in der main.cpp Quelldatei vor dem C::test Objekt initialisiert wird, dann haben Sie in der Tat seltsames Verhalten.

Wenn Sie mehrere Übersetzungseinheiten mit globalen Variablen haben, können Sie sich nicht auf die Reihenfolge der Initialisierungen zwischen ihnen verlassen.

+0

Ich es speichern, um die Deklaration von "TestObj testobj" zu "TestObj * testobj" zu ändern und die Initialisierung auf die 'main()' Methode zu verschieben, indem Sie '* testobj = TestObj()'? – martijnn2008

+0

@ martijnn2008 Ja, wenn Sie die Verwendung von Zeigern sicher betrachten. :) Die 'main'-Funktion wird immer aufgerufen, nachdem alle globalen Variablen initialisiert wurden. –

1

Dies wird durch die Initialisierungsreihenfolge der globalen statischen Variablen verursacht. Es ist nicht definiert und wird als static initialization order fiasco bezeichnet. Wenn TestObj::TestObj(C::test verwendet - ist es noch nicht konstruiert.

Der gemeinsame Weg, um es zu lösen, ist die globale statische Variable in einer Funktion lokale statische Variable zu bewegen, das heißt:

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

jetzt, wenn Sie getTestString() Testgröße gebaut werden rufen, und es wird geschehen genau einmal. Auch seit C++ 11 ist die Initialisierung von statischen Variablen in Funktionen garantiert threadsicher.

+0

Darüber hinaus ist die Verwendung von std :: cout im Konstruktor der statischen Variable unsicher, weil std :: cout selbst eine statische Variable ist, und wir sind auch auf seine Initialisierung angewiesen. –

+0

@IgorSemenov Ich habe nicht darüber nachgedacht, seit C++ 11 sieht es aus wie es behoben wurde - http://Stackoverflow.com/questions/8784892/is-stdcout-guaranteed-to-be-initialisiert – marcinj