Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ global initialization order ignores dependencies?

Tags:

I think my problem is best described in code:

#include <stdio.h>  struct Foo;  extern Foo globalFoo;  struct Foo {     Foo() {         printf("Foo::Foo()\n");     }      void add() {         printf("Foo::add()\n");     }      static int addToGlobal() {         printf("Foo::addToGlobal() START\n");          globalFoo.add();          printf("Foo::addToGlobal() END\n");          return 0;     } };  Foo globalFoo;  int dummy = Foo::addToGlobal();  int main() {     printf("main()\n");      return 0; } 

The above prints (with gcc 4.4.3):

Foo::Foo() Foo::addToGlobal() START Foo::add() Foo::addToGlobal() END main() 

This is what I expect, and seems logical.

However, when I swap the following lines:

Foo globalFoo; int dummy = Foo::addToGlobal(); 

into this:

int dummy = Foo::addToGlobal(); Foo globalFoo; 

the program outputs the following:

Foo::addToGlobal() START Foo::add() Foo::addToGlobal() END Foo::Foo() main() 

It seems instance methods of Foo are being called using an instance which has not yet been constructed! Something as simple as moving the declaration of a variable in the global scope is affecting the behaviour of the program, and that leads me to believe (1) the order of initialization of globals is not defined and (2) the order of initialization of globals ignores all dependencies. Is this correct? Is it possible to make sure the constructor of Foo is called before initializing dummy?

The problem I am trying to solve is filling a repository of items (a static instance of Foo) statically. In my current attempt, I am using a macro which (among other things) creates a global variable (in an anonymous namespace to avoid name clashing) whose initialization triggers the static initialization. Perhaps I'm tackling my problem from the wrong angle? Is there a better alternative(s)? Thanks.

like image 366
strager Avatar asked Sep 19 '10 15:09

strager


1 Answers

(1) the order of initialization of globals is not defined

Global variables in a single translation unit (source file) are initialized in the order in which they are defined.

The order of initialization of global variables in different translation units is unspecified.

(2) the order of initialization of globals ignores all dependencies

Right.

Is it possible to make sure the constructor of Foo is called before initializing dummy?

Yes, if globalFoo is defined before dummy and they are in the same translation unit.

One option would be to have a static pointer to the global instance; such a pointer will be initialized to null before any dynamic initialization takes place; addToGlobal can then test whether the pointer is null; if it is, then it is the first time the global is being used and addToGlobal can create the global Foo.

like image 87
James McNellis Avatar answered Sep 22 '22 17:09

James McNellis