...
In this noncompliant code example, the value of num_wheels
numWheels
in file1.cpp
relies on c
being initialized. However, because c
is defined in a different translation unit (file2.cpp
) than num_wheels
numWheels
, there is no guarantee that c
will be initialized by calling get_default_car()
before num_wheels
numWheels
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 num_wheelsnumWheels; public: Car() : num_wheelsnumWheels(4) {} explicit Car(int num_wheelsnumWheels) : num_wheels(num_wheelsnumWheels(numWheels) {} int get_num_wheels() const { return num_wheelsnumWheels; } }; #endif // FILE_H // file1.cpp #include "file.h" #include <iostream> extern Car c; int num_wheelsnumWheels = c.get_num_wheels(); int main() { std::cout << num_wheelsnumWheels << 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. The code for file.h
and file2.c
are unchanged; only the static num_wheels
numWheels
in file1.c
is moved into the body of a function. Consequently the initialization of num_wheels
numWheels
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 num_wheelsnumWheels; public: Car() : num_wheelsnumWheels(4) {} explicit Car(int num_wheelsnumWheels) : num_wheels(num_wheelsnumWheels(numWheels) {} int get_num_wheels() const { return num_wheelsnumWheels; } }; #endif // FILE_H // file1.cpp #include "file.h" #include <iostream> int &get_num_wheels() { extern Car c; static int num_wheelsnumWheels = c.get_num_wheels(); return num_wheelsnumWheels; } 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(); |
...