C++ FAQ Celebrating Twenty-One Years of the C++ FAQ!!!
(Click here for a personal note from Marshall Cline.)
Section 10:
10.1 What's the deal with constructors?
10.2 Is there any difference between List x; and List x();?
10.3 Can one constructor of a class call another constructor of the same class to initialize the this object? Updated!
10.4 Is the default constructor for Fred always Fred::Fred()?
10.5 Which constructor gets called when I create an array of Fred objects?
10.6 Should my constructors use "initialization lists" or "assignment"?
10.7 Should you use the this pointer in the constructor?
10.8 What is the "Named Constructor Idiom"?
10.9 Does return-by-value mean extra copies and extra overhead?
10.10 Does the compiler optimize returning a local variable by value?
10.11 Why can't I initialize my static member data in my constructor's initialization list?
10.12 Why are classes with static data members getting linker errors?
10.13 Can I add = initializer; to the declaration of a class-scope static const data member?
10.14 What's the "static initialization order fiasco"?
10.15 How do I prevent the "static initialization order fiasco"?
10.16 Why doesn't the construct-on-first-use idiom use a static object instead of a static pointer?
10.17 How do I prevent the "static initialization order fiasco" for my static data members?
10.18 Do I need to worry about the "static initialization order fiasco" for variables of built-in/intrinsic types?
10.19 How can I handle a constructor that fails?
10.20 What is the "Named Parameter Idiom"?
10.21 Why am I getting an error after declaring a Foo object via Foo x(Bar())?
10.22 What is the purpose of the explicit keyword?
[10.18] Do I need to worry about the "static initialization order fiasco" for variables of built-in/intrinsic types?

Yes.

If you initialize your built-in/intrinsic type using a function call, the static initialization order fiasco is able to kill you just as bad as with user-defined/class types. For example, the following code shows the failure:

#include <iostream>

int f();  // forward declaration
int g();  // forward declaration

int x = f();
int y = g();

int f()
{
  std::cout << "using 'y' (which is " << y << ")\n";
  return 3*y + 7;
}

int g()
{
  std::cout << "initializing 'y'\n";
  return 5;
}
The output of this little program will show that it uses y before initializing it. The solution, as before, is the Construct On First Use Idiom:
#include <iostream>

int f();  // forward declaration
int g();  // forward declaration

int& x()
{
  static int ans = f();
  return ans;
}

int& y()
{
  static int ans = g();
  return ans;
}

int f()
{
  std::cout << "using 'y' (which is " << y() << ")\n";
  return 3*y() + 7;
}

int g()
{
  std::cout << "initializing 'y'\n";
  return 5;
}
Of course you might be able to simplify this by moving the initialization code for x and y into their respective functions:
#include <iostream>

int& y();  // forward declaration

int& x()
{
  static int ans;

  static bool firstTime = true;
  if (firstTime) {
    firstTime = false;
    std::cout << "using 'y' (which is " << y() << ")\n";
    ans = 3*y() + 7;
  }

  return ans;
}

int& y()
{
  static int ans;

  static bool firstTime = true;
  if (firstTime) {
    firstTime = false;
    std::cout << "initializing 'y'\n";
    ans = 5;
  }

  return ans;
}
And, if you can get rid of the print statements you can further simplify these to something really simple:
int& y();  // forward declaration

int& x()
{
  static int ans = 3*y() + 7;
  return ans;
}

int& y()
{
  static int ans = 5;
  return ans;
}
Furthermore, since y is initialized using a constant expression, it no longer needs its wrapper function — it can be a simple variable again.