|
||||
|
Section 10:
|
[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.
|
|||