I know about the static initialization order fiasco in C++ and the
construct on first use idiom to avoid it. Thus in the code below
the global assignment of a
may happen before that of foo::a
and so
the value of a
is undefined. One the other hand, the global
assignment of b
is OK, since it invoked the function foo::b()
.
#include <iostream>
#include <string>
using namespace std;
// foo.hpp
class foo {
public:
static const string a;
static const string& b();
static const char* const c;
static const char* const d[2];
static const int e;
static const int f[2];
};
// foo.cpp
const string foo::a("astr");
const string& foo::b() {
static const string t("bstr");
return t;
}
const char* const foo::c = "cstr";
const char* const foo::d[2] = {"dstr1", "dstr2"};
const int foo::e = 5;
const int foo::f[2] = {6, 7};
// main.cpp
// global initializations
string a = foo::a; // dangerous, might be "" or "astr"
string b = foo::b(); // safe, guaranteed to be "bstr"
const char* c = foo::c; // what about these...?
const char* d = foo::d[0];
int e = foo::e;
int f = foo::f[0];
int main() {
cout << a << " " << b << "\n"
<< c << " " << d << "\n"
<< e << " " << f << "\n";
}
(Imagine I've combined foo.hpp
, foo.cpp
, and main.cpp
here.)
However what about variables which are built-in types or arrays of them?
Thus are global assignments of c
, d
, e
, and f
safe in this code?
It seems possible that the linker can set the memory for these variables
so no initialization needs to take place at run time. But can I rely on
this?
I know I shouldn't be using global variables. However, I'm the author of a library (foo.cpp and foo.hpp) and I have no control over what a user of my library (the author of main.cpp) does.
The key here is the difference between "
static
initialization" (formally known using the language of the Standard as dynamic initialization of objects with static storage duration which has the ordering fiasco) and static initialization.The Standard says (section
[basic.start.static]
) thatYour
c
,d
,e
, andf
objects have constant initializers, so their initialization is completed during the static initialization phase (even thoughc
andd
are NOT themselves constant), and their values are available during all dynamic initialization, even those that came lexically before.