...
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(); |
...