If I have some variables that I'm initializing statically (before main
begins), am I free to use any built-in stuff in these constructors, like <iostream>
or <vector>
?
The "static initialization order fiasco" occurs because the order in which static variables are initialized (among different translation units) is undefined.
So what if something benign like
std::cout << "Hello" << std::endl;
happens to rely on some static variable inside <iostream>
being initialized ahead of time? (I'm not saying it does, but assume it did.) What's to say that these static variables inside built-in libraries are initialized before my own static variables? Like inside say "Person.cpp"
or whatever.
Edit: Is std::cout guaranteed to be initialized? was suggested as a duplicate to this question. However, I think my question is slightly broader in scope because it asks about any standard built-in library, rather than just <iostream>
.
The static initialization order fiasco refers to the ambiguity in the order that objects with static storage duration in different translation units are initialized in.
Within a single compilation unit, static variables are initialized in the same order as they are defined in the source (this is called Ordered Dynamic Initialization). Across compilation units, however, the order is undefined: you don't know if a static variable defined in a.
You initialize a static object with a constant expression, or an expression that reduces to the address of a previously declared extern or static object, possibly modified by a constant expression.
Static variables are initialized only once , at the start of the execution. These variables will be initialized first, before the initialization of any instance variables. A single copy to be shared by all instances of the class. A static variable can be accessed directly by the class name and doesn't need any object.
The C++
standards make no strong statements of the behavior of the program before the start of main, or after main has completed.
In experience, I have found a number of issues where the C++ runtime has destroyed some object (e.g. resources used for management of std::mutex), which have created a deadlock in the destruction of a complex type.
I would recommend the following pattern for static's
C++ creates objects declared static in a function in the order they are executed. This leaves a pattern which will ensure that objects exist as they are needed.
AnObject * AnObject::getInstance() {
static AnObject a;
return &a;
}
This should be executed to get hold of the global, and will occur at the point when getInstance()
is called.
This code is guaranteed to be thread-safe, where if multiple threads of execution arrive in getInstance
, only one will construct the object and the rest will wait.
Creating this pattern replaces ill-defined order with thread safety issues.
Luckily, it will be possible to create a criticalsection/mutex primative in main, which is able to arbitrate.
In some OSs (e.g. InitializeCriticalSection and Windows), these locks can safely be created before main as static variables.
AnObject * AnObject::getInstance() {
EnterCriticalSection( &aObjectcrit );
static AnObject a;
LeaveCriticalSection( &aObjectcrit );
return &a;
}
Assuming you have initialized aObjectcrit either in or before this function is called.
The result of this pattern is a form of onion construction, where objects are required in the order they are needed, and when the program exits, they are destroyed in the reverse order they were created in.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With