In general, it’s pretty obvious what order the compiler will initialize variables: it’s the order in which they appear in the translation unit. What happens, though, when you have a global variable in one translation unit depending on the the initialization of a global variable in another translation unit? This little quiz explores just that.
Question: What is the result of the following code?
// Translation unit "foo.cpp" int const FOO = 1;
// Translation unit "bar.cpp" #include "foo.h" int FOO int const BAR = FOO
Answer: The result is undefined.
Why?
Translation units are not compiled in any predefined order. If bar.cpp is compiled before foo.cpp then the value of BAR will be undefined.
Can we resolve this? Well, yes!
There are many ways to solve this issue but by far the simplest is to use the Mayer’s Singleton pattern (named after Scott Mayer the acclaimed author of Effective C++). This relies on the fact that although we can’t control the order of initialization of global objects we are guaranteed that if a global function is called all members of that function (including static members) are constructed during the lifetime of that function call and if the function then returns that static member, even if it is in a different translation unit, the object being referenced will be fully constructed.
This is easier to understand with a simple code example
// Translation unit "foo.cpp" int const FOO() { static int const FOO_ = 1; return FOO_; }
// Translation unit "bar.cpp" #include "foo.h" // declares int FOO()</pre> <div id="scid:b0ad6aa8-17a2-487e-be61-3d3b25603fab:8efa9bfa-d56f-448c-8408-955224dbbf87" class="wlWriterEditableSmartContent" style="margin: 0; display: inline; float: none; padding: 0;"> <pre>int const BAR = FOO()
Of course this is a very simplistic example using an int, but this principle works with all types including user defined objects (class instances).