title: Ordered static initialization of thread-safe classes
body: <p>This post may seem overly long for just the short question at the end of it. But I also need to describe a design pattern I just came up with. Maybe it's commonly used, but I've never seen it (or maybe it just doesn't work :).</p>
  
  <p>First, here's a code which (to my understanding) has undefined behavior due to "static initialization order fiasco". The problem is that the initialization of Spanish::s_englishToSpanish is dependent on English::s_numberToStr, which are both static initialized and in different files, so the order of those initializations is undefined:</p>
  
  <p>File: English.h</p>
  
  <pre><code>#pragma once
  
  #include &lt;vector&gt;
  #include &lt;string&gt;
  
  using namespace std;
  
  struct English {
      static vector&lt;string&gt;* s_numberToStr;
      string m_str;
  
      explicit English(int number)
      {
          m_str = (*s_numberToStr)[number];
      }
  };
  </code></pre>
  
  <p>File: English.cpp</p>
  
  <pre><code>#include "English.h"
  
  vector&lt;string&gt;* English::s_numberToStr = new vector&lt;string&gt;( /*split*/
  []() -&gt; vector&lt;string&gt;
  {
      vector&lt;string&gt; numberToStr;
      numberToStr.push_back("zero");
      numberToStr.push_back("one");
      numberToStr.push_back("two");
      return numberToStr;
  }());
  </code></pre>
  
  <p>File: Spanish.h</p>
  
  <pre><code>#pragma once
  
  #include &lt;map&gt;
  #include &lt;string&gt;
  
  #include "English.h"
  
  using namespace std;
  
  typedef map&lt;string, string&gt; MapType;
  
  struct Spanish {
      static MapType* s_englishToSpanish;
      string m_str;
  
      explicit Spanish(const English&amp; english)
      {
          m_str = (*s_englishToSpanish)[english.m_str];
      }
  };
  </code></pre>
  
  <p>File: Spanish.cpp</p>
  
  <pre><code>#include "Spanish.h"
  
  MapType* Spanish::s_englishToSpanish = new MapType( /*split*/
  []() -&gt; MapType
  {
      MapType englishToSpanish;
      englishToSpanish[ English(0).m_str ] = "cero";
      englishToSpanish[ English(1).m_str ] = "uno";
      englishToSpanish[ English(2).m_str ] = "dos";
      return englishToSpanish;
  }());
  </code></pre>
  
  <p>File: StaticFiasco.h</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;tchar.h&gt;
  #include &lt;conio.h&gt;
  
  #include "Spanish.h"
  
  int _tmain(int argc, _TCHAR* argv[])
  {
      _cprintf( Spanish(English(1)).m_str.c_str() ); // may print "uno" or crash
  
      _getch();
      return 0;
  }
  </code></pre>
  
  <p>To solve the static initialization order problem, we use the construct-on-first-use idiom, and make those static initializations function-local like so:</p>
  
  <p>File: English.h</p>
  
  <pre><code>#pragma once
  
  #include &lt;vector&gt;
  #include &lt;string&gt;
  
  using namespace std;
  
  struct English {
      string m_str;
  
      explicit English(int number)
      {
          static vector&lt;string&gt;* numberToStr = new vector&lt;string&gt;( /*split*/
          []() -&gt; vector&lt;string&gt;
          {
              vector&lt;string&gt; numberToStr_;
              numberToStr_.push_back("zero");
              numberToStr_.push_back("one");
              numberToStr_.push_back("two");
              return numberToStr_;
          }());
  
          m_str = (*numberToStr)[number];
      }
  };
  </code></pre>
  
  <p>File: Spanish.h</p>
  
  <pre><code>#pragma once
  
  #include &lt;map&gt;
  #include &lt;string&gt;
  
  #include "English.h"
  
  using namespace std;
  
  struct Spanish {
      string m_str;
  
      explicit Spanish(const English&amp; english)
      {
          typedef map&lt;string, string&gt; MapT;
  
          static MapT* englishToSpanish = new MapT( /*split*/
          []() -&gt; MapT
          {
              MapT englishToSpanish_;
              englishToSpanish_[ English(0).m_str ] = "cero";
              englishToSpanish_[ English(1).m_str ] = "uno";
              englishToSpanish_[ English(2).m_str ] = "dos";
              return englishToSpanish_;
          }());
  
          m_str = (*englishToSpanish)[english.m_str];
      }
  };
  </code></pre>
  
  <p>But now we have another problem. Due to the function-local static data, neither of those classes is thread-safe. To solve this, we add to both classes a static member variable and an initialization function for it. Then inside this function we force the initialization of all the function-local static data, by calling once each function that has function-local static data. Thus, effectively we're initializing everything at the start of program, but still controlling the order of initialization. So now our classes should be thread-safe:</p>
  
  <p>File: English.h</p>
  
  <pre><code>#pragma once
  
  #include &lt;vector&gt;
  #include &lt;string&gt;
  
  using namespace std;
  
  struct English {
      static bool s_areStaticsInitialized;
      string m_str;
  
      explicit English(int number)
      {
          static vector&lt;string&gt;* numberToStr = new vector&lt;string&gt;( /*split*/
          []() -&gt; vector&lt;string&gt;
          {
              vector&lt;string&gt; numberToStr_;
              numberToStr_.push_back("zero");
              numberToStr_.push_back("one");
              numberToStr_.push_back("two");
              return numberToStr_;
          }());
  
          m_str = (*numberToStr)[number];
      }
  
      static bool initializeStatics()
      {
          // Call every member function that has local static data in it:
          English english(0); // Could the compiler ignore this line?
          return true;
      }
  };
  bool English::s_areStaticsInitialized = initializeStatics();
  </code></pre>
  
  <p>File: Spanish.h</p>
  
  <pre><code>#pragma once
  
  #include &lt;map&gt;
  #include &lt;string&gt;
  
  #include "English.h"
  
  using namespace std;
  
  struct Spanish {
      static bool s_areStaticsInitialized;
      string m_str;
  
      explicit Spanish(const English&amp; english)
      {
          typedef map&lt;string, string&gt; MapT;
  
          static MapT* englishToSpanish = new MapT( /*split*/
          []() -&gt; MapT
          {
              MapT englishToSpanish_;
              englishToSpanish_[ English(0).m_str ] = "cero";
              englishToSpanish_[ English(1).m_str ] = "uno";
              englishToSpanish_[ English(2).m_str ] = "dos";
              return englishToSpanish_;
          }());
  
          m_str = (*englishToSpanish)[english.m_str];
      }
  
      static bool initializeStatics()
      {
          // Call every member function that has local static data in it:
          Spanish spanish( English(0) ); // Could the compiler ignore this line?
          return true;
      }
  };
  
  bool Spanish::s_areStaticsInitialized = initializeStatics();
  </code></pre>
  
  <p>And here's the question: Is it possible that some compiler might optimize away those calls to functions (constructors in this case) which have local static data? So the question is what exactly amounts to "having side-effects", which to my understanding means the compiler isn't allowed to optimize it away. Is having function-local static data enough to make the compiler think the function call can't be ignored?</p>