I have seen a lot of questions on this, but none include explanation on how to compile the code for this specific use case. I run the following command: g++ main.cpp c.cpp testobj.cpp -o main, but running this gives me a Segmentation fault (core dumped). When I have the print statement in the main method in main.cpp and remove all TestObj code it does work.
Is this the proper way of assigning the C::test constant?
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";
}
testobj.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 Answers
This is caused by the initialization order of global static variables. It is undefined and is known as static initialization order fiasco. When TestObj::TestObj( uses C::test - it is not yet constructed.
The common way to solve it is to move the global static variable into a function local static variable,ie:
const std::string getTestString() {
static std::string test = "test";
return test;
}
now, when you call getTestString() test variable will be constructed, and it will be done exactly once. Also since C++11 initialization of static variables in functions is guaranteed to be thread safe.
While the order of initialization for global variables within a single translation unit is well defined, the order between translation units is not.
So if the testobj object in the main.cpp source file is initialized before the C::test object, then you will have weird behavior indeed.
If you have multiple translation units, each with global variables, then you can't rely on the initialization order between them.