"static initialization order fiasco"

Hi,
I've come to realize that I sometimes want to do advanced levels of construction/initialization in the initial part of a program, and I want this to be done automatically in libraries that I write such that I won't have to explicitly call too much in each separate program I write. For example, I might want to have a font object that has a static default font. In the initialization of that font, I might have some other objects that check to see if picture files are already made and load them or draw them if not. When I call these types of objects from inside main, there seems to be no issue. However, I'm finding that defining the static objects in global scope doesn't seem to be organized well. That is to say, if I make a class Font with a static pointer to an object of itself, say, Font* Font::defaultFont, then when I define it, the classes that I need to call to make it might not exist yet when called. I've seen something about having functions returning static objects to deal with this, but it's not clear to me where one has to put the calls to those functions. If I call a function that returns a static member from the static global definition, I still seem to be having issues. I can't tell if it's because I'm not implementing the ideas properly or if it's because the calls to those functions returning static objects are supposed to be called inside main or something. Anyway, I see another option is to make my objects constantly check to see if they are created yet and then only initialize once everything is created, but that actually has some apparent issues as well. For example, if I make a static member bool initializedFlag for all my classes, and then I have all of them check the other's status before initializing, then I seem to have strange behavior that sometimes causes a crash when the other initializedFlag doesn't exist yet. I don't know if I am missing something obvious, but it seems crazy to me that there isn't a simple and straight forward way to control what is constructed prior to main being called. Anyway, all the googling I've done has answers that I'm either missing something on or that aren't helping my specifics. Does anyone have some suggestions for how to define static global class member objects when those objects either contain other static global class member objects or rely upon other static global class member objects for creation? Wow, does that even make sense?
Okay, I've taken a look at this. I'm still not quite sure how to control the order this way. Let's say for example that I have three classes, A, B, and C. Let's suppose that A must be constructed using static member objects of B, and B must be constructed using static member objects of C. In particular, let's say that in C.cpp, I have a static definition of a map type:
map<char,string>C::mapC={make_pair('A',"letterA"),make_pair('B',"letterB"),make_pair('B',"letterB")};
Then let's say that B has a static initializer:
bool B::initializedFlag=(B::initialize(),true);
map<string,char>B::mapB=
bool B::initialize()
{
for(auto cAndS:C::mapC)
{
mapB.insert(make_pair(cAndS.second,cAndS.first));
}
}
And then let's imagine that A uses these in making a static default version of itself:
A::A()
{
callSomeFunctionUsingB(B:mapB);
}
A*A::defaultA=A();

I don't see how constructing something one time only relates to controlling C's static map being initialized before B's and both before A's defaultA. I take it it's B and C that need to have static function return values somewhere--I got that far. In fact, what I attempted to do was have the maps defined statically inside a function that returned them. However, when I tried this type of thing, I ended up getting segmentation faults. I might have had a class D that needed to be made before C too. Also, I might have made a mistake that I haven't found yet. I'll try again and see if I can get it to work. However, I think part of my issue is not understanding how defining something once changes when static class member objects are initialized relative to each other. The way it "seemed" to me from debugging was that inside the function with the static declaration, any reference to a class that hadn't happened to be declared yet in timing issues that seem out of control was causing the seg faults. I thought somehow maybe calling the function would prevent that from being an issue, but I honestly don't fully understand the order of static class member declaration and definition. I'm starting to wonder if there might be a way for me to get around all of this by untidy code that's all in one file with the right order...


Last edited on
As I'm rethinking this, I'm wondering if all I have to do is change how I define static member objects. For example, maybe I use a static function like those from the link for each definition. In this case, instead of defining the static map like this:

map<char,string>C::mapC={make_pair('A',"letterA"),make_pair('B',"letterB"),make_pair('B',"letterB")};

maybe I should:

map<char,string>C::mapC=makeMapC();
where makeMapC() is a static function:

map<char,string>&C::makeMapC()
{
static map<char,string>*tempMapSomehowForTiming=new map<char,string>({make_pair('A',"letterA"),make_pair('B',"letterB"),make_pair('B',"letterB")});
return *tempMapSomehowForTiming;
}

Is that the idea? Would it then sort itself out if I did this for all of my classes' static members?



Is that the idea? Would it then sort itself out if I did this for all of my classes' static members?


No, that is not the idea. The idea is to contain the "global objects" as static objects in a function. Not to initialize your global objects with static objects that are contained in a function.
See: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter

And then the last part of this article:
http://www.petebecker.com/js/js199905.html
In the form I’ve described, the nifty counter trick can only be used safely by implementors of the standard library. They know their compiler’s quirks, and can make sure that any peculiarities that they rely on will not be changed in some future release. There’s a slight variation that’s much more useful. It’s completely portable, because it eliminates the compiler-generated constructor and destructor calls.
Thanks for those links.
I'm not sure if I understand now, but I think maybe I'm starting to see how this could work. If I refer to a function that returns a static variable, then that should cause that static variable to be initialized prior to the function call. Is that it? Would the static members of a class initialized as a static object inside a function get initialized before the function returns a reference to that static object? Or in other words, is this saying that a way to control order of initialization is that calling a function to get a local static object reference causes that local static object to be initialized sooner than the object calling the function?


If I refer to a function that returns a static variable, then that should cause that static variable to be initialized prior to the function call. Is that it?

No. Static variables in a function are created/initialized on the first call to the function.

Would the static members of a class initialized as a static object inside a function get initialized before the function returns a reference to that static object?

Static members of a class cannot be static objects inside a function. Static variables of a class are global objects. Avoid them if initialization order matters.
> Or in other words, is this saying that a way to control order of initialization is
> that calling a function to get a local static object reference causes that local
> static object to be initialized sooner than the object calling the function?

Yes, it involves calling a function before the variable can be accessed in a translation unit.
And that function would ensure initialization prior to first use (a la std::cout)

It also involves a second function which is called after the last of the variable to perform de-initialization after last use.

The 'nifty counter' is just a counter that keeps track of the translation-unit based use count.

The technique is simple in itself; perhaps, giving an annotated code example would make the idiom clearer.

Let us say we need a class A which has a static member (say a vector of strings). And we impose this reasonable requirement: before A is used in a translation unit, it must have done #include "a.h"

Annotated code example:

Header a.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#ifndef A_H_INCLUDED
#define A_H_INCLUDED

#include <vector>
#include <string>

// note: a.h *must* be included in a translation unit prior to first use of A

struct A
{
    // ...

    static std::vector< std::string >& words ; // note: this is a reference

    // ...

    struct init // helper class to manage initialization before first use,
                // deinitialization after last use
    {
        init() { if( cnt++ == 0 ) construct_static_members() ; }
        ~init() { if( --cnt == 0 ) destroy_static_members() ; }

        init( const init& ) = delete ;
        init( init&& ) = delete ;
        init& operator= ( const init& ) = delete ;
        init& operator= ( init&& ) = delete ;

        private:
            static int cnt ; // nifty counter
            static void construct_static_members() ;
            static void destroy_static_members() ;
    };
};

namespace { const A::init A_init ; } // internal linkage; one per translation unit

#endif // A_H_INCLUDED 


Implementation a.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "a.h"
#include <new>
#include <sstream>
#include <iterator>

namespace // internal linkage
{
    // memory to hold the static member
    char static_A_vector[ sizeof( std::vector<std::string> ) ] ;
}

std::vector<std::string>& A::words = (std::vector<std::string>&) static_A_vector ;
// type-punned; this deliberately breaks strict aliasing rules
// we know it is safe here as 1. static_A_vector is not programmatically visible outside a.cc
// and 2. within a.cc it is never accessed as an array of char

int A::init::cnt ; // nifty counter default initialized to zero; we are relying on:
// "Variables with static storage duration or thread storage duration shall be zero-initialized
// before any other initialization takes place"
// ...
// "Together, zero-initialization and constant initialization are called static initialization;
// all other initialization is dynamic initialization.
// Static initialization shall be performed before any dynamic initialization takes place."
// - IS 3.6.2/2

void A::init::construct_static_members()
{
    std::istringstream stm( "the nifty counter idiom has been used in many "
                            "implementations of iostreams." ) ;
    std::istream_iterator<std::string> begin(stm), end ;
    ::new (static_A_vector) std::vector<std::string>( begin, end ) ;
}

void A::init::destroy_static_members()
{
    using type = std::vector<std::string> ;
    A::words.~type() ;
}


main.cc, a typical translation unit using A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "a.h"
#include <list>

// since we have included "a.h", static initialization of the vector
// referred to by A::words is guaranteed to have been completed by now
// constructor of const A::init A_init => would have called construct_static_members
// if nifty counter A::init::cnt was zero
// (ie. the object was not yet initialized via #include "a.h" in another translation unit)

// the technique is similar to:
// once we have #include <iostream> in our translation unit, we can safely use
// the standard stream objects (std::cin, std::cout etc.) with the absolute
// guarantee that a. they would have been constructed before our code uses them
// and b. they would not be destroyed before our code has finished using them
// the requirement is that we *must* #include <iostream> to be able to use them.
// the only real difference is that the implementor of the standard library might
// have written code that is not quite so elaborate and portable.
// The library implementor knows all about the specific compiler being used,
// and can take advantage of that particular compiler’s implementation details

std::list<std::string> dict( A::words.begin(), A::words.end() ) ;

#include <iostream>

int main()
{
    for( const auto& word : dict ) std::cout << word << ' ' ;
    std::cout << '\n' ;
}


Put these together into a program, build and run it, and try to follow what is going on.
Thanks!
I'll have a play with this...
Okay, I'm not sure if I'm missing something, but it seems to me this is calling constructors to get them to run first via the line:
namespace { const A::init A_init ; } // internal linkage; one per translation unit

Let me do something similar, expanding upon what is done here to illustrate my what I still don't understand:

A.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef A_H
#define A_H
#include <vector>
#include <string>
#include <iostream>
#include <map>
using namespace std;
struct A
{
    A();
    static std::vector< std::string >& words;
    static map<char, string>mapCharToString;
    struct init
    {
        init();
        ~init();
        init(const init&) = delete;
        init(init &&) = delete;
        init& operator=(const init&) = delete;
        init& operator=(init &&) = delete;
    private:
        static int cnt;
        static void construct_static_members();
        static void destroy_static_members();
    };
};
const A anotherA;
const A::init A2_init;
#endif 


A.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include "A.h"
#include <new>
#include <sstream>
#include <iterator>
//namespace
//{
char static_A_vector[ sizeof( std::vector<std::string>) ];
//}
std::vector<std::string>& A::words=(std::vector<std::string>&) static_A_vector;
int A::init::cnt;
map<char,string>A::mapCharToString={make_pair('A',"letterA"),make_pair('B',"letterB"),make_pair('C',"letterC")};
void A::init::construct_static_members()
{
    cerr<<"starting void A::init::construct_static_members(), step 1 void A::init::construct_static_members(), &A::words="<<&A::words<<endl;

    cerr<<"A::mapCharToString.size()="<<A::mapCharToString.size()<<endl;
    std::istringstream stm("the nifty counter idiom has been used in many implementations of iostreams.");
    cerr<<"step 2 void A::init::construct_static_members(), &A::words="<<&A::words<<endl;
    std::istream_iterator<std::string> begin(stm),end;
    cerr<<"step 3 void A::init::construct_static_members(), &A::words="<<&A::words<<endl;
    ::new (static_A_vector)std::vector<std::string>(begin,end);
    cerr<<"finishing void A::init::construct_static_members(), &A::words="<<&A::words<<endl;
}
void A::init::destroy_static_members()
{
    cerr<<"starting void A::init::destroy_static_members(), step 1 void A::init::destroy_static_members(), &A::words="<<&A::words<<endl;
    cerr<<"A::mapCharToString.size()="<<A::mapCharToString.size()<<endl;
    A::words.~vector();
    cerr<<"finishing void A::init::destroy_static_members(), &A::words="<<&A::words<<endl;
}
A::init::init()
{
    cerr<<"starting init(), step 1 init(), cnt="<<cnt<<", &A::words="<<&A::words<<endl;
    cerr<<"A::mapCharToString.size()="<<A::mapCharToString.size()<<endl;
    if(cnt++ ==0)
    {
        cerr<<"cnt++==0 and now cnt="<<cnt<<", &A::words="<<&A::words<<", step 2 init(), call construct_static_members"<<endl;
        construct_static_members();

    }
    else
    {
        cerr<<"cnt++!=0 and now cnt="<<cnt<<", &A::words="<<&A::words<<endl;
    }
    cerr<<"A::mapCharToString.size()="<<A::mapCharToString.size()<<endl;
    cerr<<"finishing init(), &A::words="<<&A::words<<endl;
}
A::init::~init()
{
    cerr<<"starting ~init(), step 1 ~init(), cnt="<<cnt<<", &A::words="<<&A::words<<endl;
    cerr<<"A::mapCharToString.size()="<<A::mapCharToString.size()<<endl;
    if(--cnt==0)
    {
        cerr<<"--cnt==0 and now cnt="<<cnt<<", &A::words="<<&A::words<<", step 2 ~init(), call destroy_static_members"<<endl;
        destroy_static_members();
    }
    else
    {
        cerr<<"--cnt!=0 and now cnt="<<cnt<<", &A::words="<<&A::words<<endl;
    }
    cerr<<"A::mapCharToString.size()="<<A::mapCharToString.size()<<endl;
    cerr<<"finishing ~init(), &A::words="<<&A::words<<endl;
}
A::A()
{
    cerr<<endl<<"starting A::A()"<<endl;
    cerr<<"A::mapCharToString.size()="<<A::mapCharToString.size()<<endl;
    cerr<<"finishing A::A()"<<endl<<endl;
}


B.h
1
2
3
4
5
6
7
8
9
10
11
#ifndef B_H
#define	B_H
#include"A.h"
class B
{
public:
    B();
};
const A firstA;
const A::init A1_init;
#endif	/* B_H */ 


B.cpp
1
2
3
4
5
#include "A.h"
#include "B.h"
B::B()
{
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "B.h"
#include "A.h"
#include <list>
std::list<std::string> dict(A::words.begin(),A::words.end());
#include <iostream>
#include <map>
extern char static_A_vector[ sizeof( std::vector<std::string>) ];
int main()
{    
    cerr<<"starting int main(), &A::words="<<&A::words<<", &static_A_vector="<<&static_A_vector<<endl;   
    cerr<<"A::mapCharToString.size()="<<A::mapCharToString.size()<<endl;
    //cerr<<"anotherA.mapCharToString.size()="<<anotherA.mapCharToString.size()<<endl;
    cerr<<"****************************************************************************************************"<<endl;
    for(const auto& word:dict)
    {
        std::cout<<word<<' ';
    }
    std::cout<<'\n';
    cerr<<"****************************************************************************************************"<<endl;
    cerr<<"finishing int main(), &A::words="<<&A::words<<", &static_A_vector="<<&static_A_vector<<endl;
}

Last edited on


starting A::A()
A::mapCharToString.size()=0
finishing A::A()

starting init(), step 1 init(), cnt=0, &A::words=0x1038fbd10
A::mapCharToString.size()=0
cnt++==0 and now cnt=1, &A::words=0x1038fbd10, step 2 init(), call construct_static_members
starting void A::init::construct_static_members(), step 1 void A::init::construct_static_members(), &A::words=0x1038fbd10
A::mapCharToString.size()=0
step 2 void A::init::construct_static_members(), &A::words=0x1038fbd10
step 3 void A::init::construct_static_members(), &A::words=0x1038fbd10
finishing void A::init::construct_static_members(), &A::words=0x1038fbd10
A::mapCharToString.size()=0
finishing init(), &A::words=0x1038fbd10

starting A::A()
A::mapCharToString.size()=3
finishing A::A()

starting init(), step 1 init(), cnt=1, &A::words=0x1038fbd10
A::mapCharToString.size()=3
cnt++!=0 and now cnt=2, &A::words=0x1038fbd10
A::mapCharToString.size()=3
finishing init(), &A::words=0x1038fbd10

starting A::A()
A::mapCharToString.size()=3
finishing A::A()

starting init(), step 1 init(), cnt=2, &A::words=0x1038fbd10
A::mapCharToString.size()=3
cnt++!=0 and now cnt=3, &A::words=0x1038fbd10
A::mapCharToString.size()=3
finishing init(), &A::words=0x1038fbd10

starting A::A()
A::mapCharToString.size()=3
finishing A::A()

starting init(), step 1 init(), cnt=3, &A::words=0x1038fbd10
A::mapCharToString.size()=3
cnt++!=0 and now cnt=4, &A::words=0x1038fbd10
A::mapCharToString.size()=3
finishing init(), &A::words=0x1038fbd10

starting A::A()
A::mapCharToString.size()=3
finishing A::A()

starting init(), step 1 init(), cnt=4, &A::words=0x1038fbd10
A::mapCharToString.size()=3
cnt++!=0 and now cnt=5, &A::words=0x1038fbd10
A::mapCharToString.size()=3
finishing init(), &A::words=0x1038fbd10
starting int main(), &A::words=0x1038fbd10, &static_A_vector=0x1038fbd10
A::mapCharToString.size()=3
****************************************************************************************************
the nifty counter idiom has been used in many implementations of iostreams. 
****************************************************************************************************
finishing int main(), &A::words=0x1038fbd10, &static_A_vector=0x1038fbd10
starting ~init(), step 1 ~init(), cnt=5, &A::words=0x1038fbd10
A::mapCharToString.size()=3
--cnt!=0 and now cnt=4, &A::words=0x1038fbd10
A::mapCharToString.size()=3
finishing ~init(), &A::words=0x1038fbd10
starting ~init(), step 1 ~init(), cnt=4, &A::words=0x1038fbd10
A::mapCharToString.size()=3
--cnt!=0 and now cnt=3, &A::words=0x1038fbd10
A::mapCharToString.size()=3
finishing ~init(), &A::words=0x1038fbd10
starting ~init(), step 1 ~init(), cnt=3, &A::words=0x1038fbd10
A::mapCharToString.size()=3
--cnt!=0 and now cnt=2, &A::words=0x1038fbd10
A::mapCharToString.size()=3
finishing ~init(), &A::words=0x1038fbd10
starting ~init(), step 1 ~init(), cnt=2, &A::words=0x1038fbd10
A::mapCharToString.size()=3
--cnt!=0 and now cnt=1, &A::words=0x1038fbd10
A::mapCharToString.size()=3
finishing ~in
it(), &A::words=0x1038fbd10
starting ~init(), step 1 ~init(), cnt=1, &A::words=0x1038fbd10
A::mapCharToString.size()=3
--cnt==0 and now cnt=0, &A::words=0x1038fbd10, step 2 ~init(), call destroy_static_members
starting void A::init::destroy_static_members(), step 1 void A::init::destroy_static_members(), &A::words=0x1038fbd10
A::mapCharToString.size()=3
finishing void A::init::destroy_static_members(), &A::words=0x1038fbd10
A::mapCharToString.size()=3
finishing ~init(), &A::words=0x1038fbd10


What I've done here is use the const declaration in the header to get A's constructor called when I want it called. However, the static members of A such as the map are not initialized yet. I'm trying to figure out how to get them to be initialized prior to the constructor. Maybe I'll have to reorganized them to be objects that get constructed and then repeat this process on them first? Or maybe I should just move the initialization of them into constructor. It seems weird to me, but I guess it could be done.

Furthermore, I'm not understanding why
1
2
const A anotherA;
const A::init A2_init;

are not double symbols seeing as A.cpp and B.cpp both compile them.
Usually if I define something in a header and reference it from more than one source file, it causes a double symbol issue...
>
1
2
3
4
//namespace
//{
char static_A_vector[ sizeof( std::vector<std::string>) ];
//} 


> extern char static_A_vector[ sizeof( std::vector<std::string>) ];

Do not, repeat DO NOT, do this.
The array holding memory for the object must have internal linkage.

Put it back in the anonymous namespace, and remove the extern declaration from every other translation unit.



> However, the static members of A such as the map are not initialized yet.

You need to repeat what has been done for static std::vector< std::string >& words; for the map (for every static member).

1. Declare the static member as a reference in A
2. Set aside memory to hold the map in a.cc (an array of char with internal linkage)
3. Type-pun the reference to the map to refer to the array holding memory for the map
4. Add code to construct and initialize the map in void A::init::construct_static_members()
5. Add code to destroy the map in void A::init::destroy_static_members()



> Furthermore, I'm not understanding why ...

const A anotherA; What is this doing in a.h?
Remove, repeat remove it.

And remove all this junk from b.h and every other header.
1
2
const A firstA;
const A::init A1_init;


The only place where you define an object of type A::init is in a.h
And define it with internal linkage.

There needs to be only one object of type A::init in a translation unit; and that is defined when a.h is included.

It does not cause a linker error because it has internal linkage.
Read: http://stackoverflow.com/questions/1358400/what-is-external-linkage-and-internal-linkage-in-c
That internal linkage bit is fascinating. I'll have to think about it longer to fully understand it. I guess the point is that it's the opposite of global.

I think I see how to use the functions that return static variables to solve my issue now:

I change this in A.cpp
1
2
3
4
5
6
7
8
std::vector<std::string>& A::words=(std::vector<std::string>&) static_A_vector;
int A::init::cnt;
map<char,string>& A::initializeMap()
{
    static map<char,string>*newMap=new map<char,string>({make_pair('A',"letterA"),make_pair('B',"letterB"),make_pair('C',"letterC")});
    return *newMap;
}
map<char,string>A::mapCharToString=A::initializeMap();

and
1
2
3
4
5
6
7
8
9
A::A()
{
    cerr<<endl<<"starting A::A()"<<endl;
    cerr<<"A::mapCharToString.size()="<<A::mapCharToString.size()<<endl;
    cerr<<"mapCharToString= A::initializeMap();"<<endl;
    mapCharToString= A::initializeMap();
    cerr<<"A::mapCharToString.size()="<<A::mapCharToString.size()<<endl;    
    cerr<<"finishing A::A()"<<endl<<endl;
}

then my output starts with:

starting A::A()
A::mapCharToString.size()=0
mapCharToString= A::initializeMap();
A::mapCharToString.size()=3
finishing A::A()

Which solves my problem when the map gets initialized.
I guess the value in the call of a function that returns a local statically initialized variable reference is that it can be called again to get the same result.
This is all very interesting.
Honestly, I'm not finished wrapping my mind around this, but I think I know what I have to do now--I see light at the end of the tunnel...
> That internal linkage bit is fascinating.
> I'll have to think about it longer to fully understand it.

Do that. A clear understanding of linkage is an essential requirement for writing any C++ (or C) program which has more than one translation unit .
http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=41
I see, so the anonymous namespace
 
namespace { const A::init A_init ; } // internal linkage; one per translation unit 

is a way of calling a constructor in a header without running into duplicate objects. That's very useful!
Topic archived. No new replies allowed.