I'm trying to make a global instance of a class whose constructor references a global variable.
The program compiles without error. But when it is run, it crashes on the reference of the global variable.
How do I create a global instance of this class without the constructor crashing it?
Here is the SSCCE that I made:
/* main.cpp */
#include "TestClass.h"
// I need a global instance of TestClass
TestClass j;
int main()
{
return 0;
}
-
/* C.h */
#ifndef C_H_INCLUDED
#define C_H_INCLUDED
#include <string>
// global
extern const std::string S;
#endif // C_H_INCLUDED
-
/* C.cpp */
#include "C.h"
#include <string>
// extern definition of global
const std::string S = "global string data";
-
/* TestClass.h */
#ifndef TESTCLASS_H_INCLUDED
#define TESTCLASS_H_INCLUDED
class TestClass
{
public:
TestClass();
};
#endif // TESTCLASS_H_INCLUDED
-
/* TestClass.cpp */
#include "TestClass.h"
#include <iostream>
#include "C.h" // for S global
TestClass::TestClass()
{
std::cout << S << std::endl; // this line crashes the program
}
Debugger messages about crash:
Program received signal SIGSEGV, Segmentation fault.
In std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) () ()
#1 0x004014f9 in TestClass::TestClass (this=0x4a0024 <j>) at E:\cpp\externconsttest\TestClass.cpp:9
E:\cpp\externconsttest\TestClass.cpp:9:117:beg:0x4014f9
At E:\cpp\externconsttest\TestClass.cpp:9
#1 0x004014f9 in TestClass::TestClass (this=0x4a0024 <j>) at E:\cpp\externconsttest\TestClass.cpp:9
E:\cpp\externconsttest\TestClass.cpp:9:117:beg:0x4014f9
This example crashes in operator<<, but it crashes on any reference to S no matter how it's referenced.
I guess that it crashes because the global
const std::string S
is not initialized yet at the time when contructor of yourTestClass
is called. This is a general problem with global and static variables in C++: in general you do not know in which order global and static variables are initialized (actually they are initialized in order in which you pass object files to linker at linking stage - but that is not very helpful). There are a few different solutions to this problem. One of them is:Create a function with a static variable in its body that returns a reference to the variable (instead of just using global variable you would call that function). This is simmilar to the singleton design pattern:
const std::string& get_my_string() { static const std::string S; return S; }
Then in your constructor:
Calling
get_my_string
will force the initialization of your static string only once (the first time the function is called) exactly at the time when you need it. Please notice that this example does not take threads into account (in a multi-threaded application you should synchronize theget_my_string()
function to protect initialization of the static string).I hope that helps.
By the way: you may get simmilar problems with your global
TestClass j
.This way you are going to solve only half of the problem - initialization (you still don't know the order of destruction) - in most cases is it sufficient though.
Another option would be to create the string on heap (probably using simmilar approach as described above) - you just have to
delete
it at the time you know it is safe to do so.