9

I have a piece of code structured like this:

a.cpp:  
    #include "b.hpp"  
    const unsigned a =  create(1);


b.cpp:
    map<int, string> something; // global variable
    unsigned create(unsigned a){
        something.insert(make_pair(a, "somestring"));
        return a;
    }

Now, this throws out a segfault, valgrind says that map was not yet created. How does it work, how should I change it?

darenn
  • 469
  • 5
  • 17

4 Answers4

11

C++ does not define an order for when global variables are constructed during program startup. a could be initialized first before something gets constructed which would cause the problem above. When you start constructing global variables that depend on other global variables being initialized then you run into the classical static initialization order fiasco.

An easy way to fix your above scenario is to make something static and move it into your create function.

unsigned create(unsigned a)
{
    static map<int, string> something;
    something.insert(make_pair(a, "somestring"));
    return a;
}

That will guarantee something gets created on first call to create.

greatwolf
  • 20,287
  • 13
  • 71
  • 105
9

All global variables are created before entering the main(), but their order of construction between different translation units is not specified by the c++ standard. Their order of construction within the same translation unit is in order of specification.

You could form something that is guarantied by the standard. Something like this :

map<int, string>& mymap(){
    static map<int, string> something;
    return something;
}

unsigned create( unsigned a ) {
    mymap().insert(make_pair(a, "somestring"));
    return a;
}

The map something is created the first time function mymap() is called.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • 2
    Global variables within each translation unit are constructed in order of their declaration. The order **between** translation units is, indeed, not specified. – Pete Becker Oct 27 '13 at 14:06
  • 1
    They're not even required to be "constructed" (dynamically initialized) before entering `main`, see [basic.start.init]/4. To add further complication, static data member of not explicitly specialized class templates have unordered initialization, everything else has ordered initialization (within a TU). – dyp Oct 27 '13 at 14:34
3

The order, in which global variables from different translation units (i.e. located in different *.cpp files) are initialized is not defined by the standard. Thus, relying on it is undefined behaviour. See also:

Community
  • 1
  • 1
vines
  • 5,160
  • 1
  • 27
  • 49
2

The order in which global variables (that is, variables at namespace scope) is created is specified at being:

  • the order in which they appear, in a translation unit
  • unspecified, from one translation unit to another

This is something that languages with modules do not suffer, but unfortunately a common issue in C++. Using function-local static variables, one can get initialization on first use, which generally solves this issue.

Example of static local:

int func(int a) {
    static std::map<int, int> m;
    return m[a] = m.size();
}
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 1
    "the order in which they appear, in a translation unit" unless they're static data members of not explicitly specialized class templates (for dynamic initialization). – dyp Oct 27 '13 at 14:38