C ++ crashes when creating a global instance of a class whose constructor references a global variable

I am trying to create a global instance of a class whose constructor refers to a global variable.

The program compiles without errors. But when it starts, it is reset by reference to a global variable.

How to create a global instance of this class without destroying its constructor?

Here is the SSCCE I made:

/* main.cpp */ #include "TestClass.h" // I need a global instance of TestClass TestClass j; int main() { return 0; } 

-

 /* Ch */ #ifndef C_H_INCLUDED #define C_H_INCLUDED #include <string> // global extern const std::string S; #endif // C_H_INCLUDED 

-

 /* C.cpp */ #include "Ch" #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 "Ch" // for S global TestClass::TestClass() { std::cout << S << std::endl; // this line crashes the program } 

Debugger Debug Messages:

 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 the <<statement, but it crashes with any reference to S no matter how it refers.

+5
source share
2 answers

I assume it will work because the global const std::string S is not yet initialized at the time the constructor of your TestClass . This is a common problem with global and static variables in C ++: in the general case, you don’t know in which order the global and static variables are initialized (in fact, they are initialized in the order in which you transfer the object files to the linker at the linking stage), but this is not very useful). There are several different solutions to this problem. One of them:

  • Create a function with a static variable in your body that returns a reference to the variable (instead of just using the global variable that you would call this function). This is comparable to a singleton design template:

    const std::string& get_my_string() { static const std::string S; return S; }

Then in your constructor

 TestClass::TestClass() { std::cout << get_my_string() << std::endl; } 

Calling get_my_string will force your static string to be initialized only once (when you first call the function) exactly at the time you need it. Note that this example does not account for threads (in a multi-threaded application, you must synchronize the get_my_string() function to protect the initialization of a static string).

I hope this helps.

By the way: you may have problems with your global TestClass j .

Thus, you will solve only half of the problem - initialization (you still do not know the order of destruction) - in most cases this is enough.

Another option is to create a string on the heap (possibly using a similar approach as described above) - you just need to delete while you know that it is safe.

+4
source

C ++ does not provide symantics for ctor sequence control for global scope objects in different compilation units. In addition, the next assembly may change the sequence.

The mechanism we use:

  • create global area pointers initialized to null ptr.

and

  • After the main launches, but before the start of any flows, new objects in a rational order.

So in this case ...

 TestClass* j = nullptr; int main(...) { // .. other init /* const std::string* */ S = new std::string ("global string data"); // now that S exists, it is ok to intantiate: /* TestClass() */ j = new TestClass; // much more stuff return(0); } 

Explicit control can always be made to work.

Another advantage is the constant start time.

Related Information - Most template templates are not thread safe. Combining multiple threads without managing global containers can be very difficult to debug.

+1
source

All Articles