c++staticinitializationstatic-order-fiasco

Static initialization order fiasco


In his "Thinking in C++" (Chapter 10) Eckel describes a technique that was pioneered by Jerry Schwarz to solve the fiasco. He says that if we want to initialize x to 100 and y to 200 and share them among all translation units, we create an Initializer.h that looks like this:

extern int x;
extern int y;
class Initializer {
   static int initCount;
   // if (initCount++ == 0) x = 100 & y = 200
   /* ... */
};
static Initializer init;

And in implementation file we have

#include "Initializer.h"
int x;
int y;
int Initializer::initCount;

and Eckel says that "static initialization (in implementation file) will force all these values to zero".

Let me consider the following case: the compiler processes the implementation file after some other file with that header included (it means that x and y have been already set to 100 and 200 in that other file). The compiler sees int x, so what will it do? Will it set x and y to zero eliminating initialization and all possible changes in previous files? But if it does, then initCount will also be set to zero, breaking down the whole technique.


Solution

  • But if it is true, and the compiler handles the implementation file after some another file, than it will set x and y to zero eliminating initialization and all possible changes in previous files?

    I'm not sure what you mean by this. If x and y are defined in other files, then you have a linker clash and the program simply won't compile.

    If x, y and most importantly Initializer::initCount are implemented in this way, there will be unique instances of them in the program; they are effectively global and will be initialized to 0 at program start, before any Initializer is constructed (due to inclusion of the header declaring a static instance of that class). Each construction of a static Initializer will first check whether any other Initializers have been constructed due to the if (initCount++ == 0) etc.

    The first Initializer ctor to run (still before entering main) will thus set all three values.