The eThe C++ Standard, [stmt.dcl], paragraph 4 [ISO/IEC 14882-2014], states:
...
In this noncompliant code example, the value of numWheels
num_wheels
in file1.cpp
relies on c
being initialized. However, because c
is defined in a different translation unit (file2.cpp
) than numWheels
num_wheels
, there is no guarantee that c
will be initialized by calling get_default_car()
before numWheels
num_wheels
is initialized by calling c.get_num_wheels()
. This is often referred to as the "static initialization order fiasco", and the resulting behavior is unspecified.
Code Block | ||||
---|---|---|---|---|
| ||||
// file.h #ifndef FILE_H #define FILE_H class Car { int numWheelsnum_wheels; public: Car() : numWheelsnum_wheels(4) {} explicit Car(int numWheelsnum_wheels) : numWheels(numWheelsnum_wheels(num_wheels) {} int get_num_wheels() const { return numWheelsnum_wheels; } }; #endif // FILE_H // file1.cpp #include "file.h" #include <iostream> extern Car c; int numWheelsnum_wheels = c.get_num_wheels(); int main() { std::cout << numWheelsnum_wheels << std::endl; } // file2.cpp #include "file.h" Car get_default_car() { return Car(6); } Car c = get_default_car(); |
...
This compliant solution uses the "construct on first use" idiom to resolve the static initialization order issue. Because the numWheels
num_wheels
object was moved into the body of a function, its initialization is guaranteed to happen when control flows over the point of declaration, ensuring control over the order. The global object c
is initialized before execution of main()
begins, so by the time get_num_wheels()
is called, c
is guaranteed to have already been dynamically initialized.
Code Block | ||||
---|---|---|---|---|
| ||||
// file.h #ifndef FILE_H #define FILE_H class Car { int numWheelsnum_wheels; public: Car() : numWheelsnum_wheels(4) {} explicit Car(int numWheelsnum_wheels) : numWheels(numWheelsnum_wheels(num_wheels) {} int get_num_wheels() const { return numWheelsnum_wheels; } }; #endif // FILE_H // file1.cpp #include "file.h" #include <iostream> int &get_num_wheels() { extern Car c; static int numWheelsnum_wheels = c.get_num_wheels(); return numWheelsnum_wheels; } int main() { std::cout << get_num_wheels() << std::endl; } // file2.cpp #include "file.h" Car get_default_car() { return Car(6); } Car c = get_default_car(); |
...