Say I have defined a variable like this (C++):
static const char str[] = "Here is some string data";
And I have a statically allocated class instance which references this array in its destructor, can this go wrong? E.g. could the str variable somehow get invalid?
class A {
~A() {
cout << str << endl;
}
};
static A a;
My assumption is that it can't go wrong, but I can find it clearly stated anywhere. I want to know this for sure. My assumption is that we can not predict the sequence in which destructors for statically allocated objects are called but that the data itself is never really freed until the process is torn down. Meaning pointers to POD should be safe, but not object instances.
Meaning e.g. this:
static const QString str = "Here is some string data";
or
static const std::string str = "Here is some string data";
Can not safely be used in A's destructor because they both allocate their string data on the heap and this might be freed by the destructor before A's destructor is called.
Is my assumption right and are there any sections in the C++ standard explaining this or some link to some other authority who can verify this?
The order in which destructors for automatic, global, and static objects are called is always well defined: it's the reverse of the order in which the constructors were called. So if object A
references an object B
and B
was constructed before A
, you can be sure that B
is destructed after A
. That leaves us with the question of the order of constructors.
Here's what I remember:
- Global and static objects are constructed before
main()
is called.
- Class-local statics are constructed before any object of their class.
- Function-local statics are constructed when their scope is reached for the first time.
- Global and static objects within the same translation unit are constructed in the order they are defined. (That means that the order of inclusion of headers might affect this!)
- The order of construction of global and static objects across translation units is undefined.
I'm a bit hazy on some of these, so please correct me if you think this isn't right.
Okay I tried to read the C++ standard myself to find some answers. I see from the answers I get that there is a lot of confusion about difference between constructing an object and allocating it.
From the standard:
3.6.2
Initialization of non-local objects
Objects with static storage duration
(3.7.1) shall be zero-initialized
(8.5) before any other initialization
takes place. A reference with static
storage duration and an object of POD
type with static storage duration can
be initialized with a constant
expression (5.19); this is called
constant initialization. Together,
zero-initialization and constant
initialization are called static
initialization; all other
initialization is dynamic
initialization. Static initialization
shall be performed before any dynamic
initialization takes place. Dynamic
initialization of an object is either
ordered or unordered.
My interpretatio of this is that a const char[] will always be guaranteed to have been set before any constructor is run.
3.6.3 Termination
Destructors (12.4) for initialized objects of static storage duration (declared at block scope or at namespace scope) are
called as a result of returning from main and as a result of calling std::exit (18.3). These objects are destroyed in the
reverse order of the completion of their constructor or of the completion of their dynamic initialization. If an object is
initialized statically, the object is destroyed in the same order as if the object was dynamically initialized.
From what I can read from this POD types with constant expression will be initialized before any object types and destroyed after any object types. Meaning no code will run that can access them while they are not valid.
Which should explain why Google's C++ code standard says you should only use POD types with constant expressions.:
As a result we only allow static variables to contain POD data. This rule completely disallows vector (use C arrays instead), or string (use const char []).
If I remember correctly, global object initialization is not defined in the standard (or poorly defined) making global objects hard to reference each other.
If you want to be sure about initialization order, use a global function with your static object in it, that just return it. You're now garanteed that the static object will be initialized on first function call.
Destruction will occur at the end of the application, once out of main().