Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: s/numWheels/num_wheels/g;

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

...