Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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
bgColor#FFCCCC
langcpp
// 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
bgColor#ccccff
langcpp
// 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();

...