A recent question drew my attention to the way that constexpr has changed in C++14. The new feature is that a non-local variable with static storage duration may be initialized in the static initialization phase if its initializer consists of a constexpr constructor, even if the type of the variable isn't a literal type. More precisely, the new wording in [basic.start.init] is:
A constant initializer for an object o is an expression that is a constant expression, except that it may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types [Note: such a class may have a non-trivial destructor — end note]. Constant initialization is performed [...] if an object with static or thread storage duration is initialized by a constructor call, and if the initialization full-expression is a constant initializer for the object [...]
The typical example is std::unique_ptr, which "should never be worse that hand-written":
std::unique_ptr<int> p; // statically initialized by [unique.ptr.single.ctor],
// requires no code excution
int main()
{
p = std::make_unique<int>(100);
}
// p is destroyed eventually
Prior to this addition, statically initialized variables were either of reference type or of literal object type, and therefore had trivial destructors. But now a statically initialized global variable can have a non-trivial destructor.
How is such a destructor call ordered with respect to the destructors of dynamically initialized global objects, with respect to other statically initialized ones, and how are the destructor calls sequenced?
Consider
If an object is initialized statically, the object is destroyed in the
same order as if the object was dynamically initialized.
and
If the completion of the constructor or dynamic initialization of an
object with static storage duration is sequenced before that of
another, the completion of the destructor of the second is sequenced
before the initiation of the destructor of the first.
Now,
Static initialization shall be performed before any dynamic
initialization takes place.
Clearly this answers the first question: Since p is guaranteed to be initialized before any dynamic initialization is performed, the destructor is called after any dynamically initialized object is destroyed.
Essentially the second question, i.e. what order the destructions of several statically initialized variables have, is reduced to the ordering of the initialization of these:
Dynamic initialization of a non-local variable with static storage
duration is either ordered or unordered. Definitions of explicitly
specialized class template static data members have ordered
initialization. Other class template static data members (i.e.,
implicitly or explicitly instantiated specializations) have unordered
initialization. Other non-local variables with static storage
duration have ordered initialization.
The bold sentence includes all statically initialized objects that are not static data members of instantiated classes. They are ordered within one translation unit:
Variables with ordered initialization defined within a single
translation unit shall be initialized in the order of their
definitions in the translation unit.
So, to summarize:
Variables which are subject of static initialization and are not static data members of an instantiated class are destroyed in the reverse order of definition in a translation file.
... those variables are always destroyed after any dynamically initialized object is destroyed.
However, despite possible argumentative mistakes, neither Clang nor GCC seem to implement it this way at the moment: Demo.
[basic.start.term]/1 (N4140) says:
If an object is initialized statically, the object is destroyed in the same order as if the object was dynamically initialized.
As I understand, this means that for the purpose of determinig the order of destruction, all static initialization is treated as dynamic (ordered or unordered) and the destructors are called in reverse order of this initialization.
Related
Is the following code valid, e.g. doesn't bring undefined behaviour?
struct S
{
int i = s.i;
static S s;
};
S S::s;
int main()
{
S a; // a.i = 0
S::s.i = 42;
S b; // b.i = 42
}
As far as I know all variables with static storage duration are zero initialized. Hence s.i is 0 on S::s creation, and all is good. But maybe I'm missing something.
I would argue it's well defined.
[class.static.data]/6
Static data members are initialized and destroyed exactly like
non-local variables.
[basic.start.static]/2 (emphasis mine)
A constant initializer for a variable or temporary object o is an
initializer whose full-expression is a constant expression, except
that if o is an object, such an initializer may also invoke constexpr
constructors for o and its subobjects even if those objects are of
non-literal class types. [ Note: Such a class may have a non-trivial
destructor. — end note ] Constant initialization is performed if a
variable or temporary object with static or thread storage duration is
initialized by a constant initializer for the entity. If constant
initialization is not performed, a variable with static storage
duration or thread storage duration is zero-initialized. Together,
zero-initialization and constant initialization are called static
initialization; all other initialization is dynamic initialization.
All static initialization strongly happens before ([intro.races]) any dynamic initialization. [ Note: The dynamic initialization of
non-local variables is described in [basic.start.dynamic]; that of
local static variables is described in [stmt.dcl]. — end note ]
[dcl.init]/6 (emphasis mine)
To zero-initialize an object or reference of type T means:
if T is a scalar type, the object is initialized to the value obtained by converting the integer literal 0 (zero) to T;
if T is a (possibly cv-qualified) non-union class type, each non-static data member, each non-virtual base class subobject, and, if
the object is not a base class subobject, each virtual base class
subobject is zero-initialized and padding is initialized to zero bits;
if T is a (possibly cv-qualified) union type, the object's first non-static named data member is zero-initialized and padding is
initialized to zero bits;
if T is an array type, each element is zero-initialized;
if T is a reference type, no initialization is performed.
Because int i = s.i; means s.i goes through dynamic initialization, it's guaranteed to be zero initialized beforehand. So when it'll be used to initialize itself later, it's value won't be indeterminate. A 0 is to be expected.
You are missing something. Variables with static storage duration are zeroed, and then their constructor is called.
What I can't quite tell is whether the initialization of S.i with the value of S.i is undefined behaviour (because S.i is not initialized at this point) or not (because it must be zero).
Edit: The code in Defect Report 2026 is very similar in effect to this, and is declared to be ill-formed (which means the compiler must error). My suspicion is that the intention of the committee is that the OP's code is undefined behaviour.
Edit 2: The above DR refers to constexpr values. That probably changes things enough that is irrelevant.
Having said that: if you are relying on very careful reading of the standard to make your code legal, you are relying on the compiler author to have read it as carefully. You may be right, but that doesn't help in the short-term if the compiler author has misread and implemented something else (although hopefully, they will eventually fix the bug).
Some relevant excerpts from the C++ standard 1998:
The storage for objects with static storage duration shall be zero-initialized before any other initialization takes place. Zero-initialization and initialization with constant expression are collectively called static initialization; all other initialization is dynamic initialization. Objects of POD types with static storage duration initialized with constant expressions shall be initialized before any dynamic initialization takes place. Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit.
It is implementation-defined whether or not the dynamic initialization of an object of namespace scope is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized.
Consider the following code.
int a = 1;
int main()
{
cout << a << endl;
return 0;
}
According to the standard, the static initialization takes place before the dynamic initialization, and the dynamic initialization may take place after main() is entered. My question is: is the global variable a initialized to be 1 before main() is entered? Then if all the threads are created after main() is entered the static initialization of global variables is guaranteed to be thread-safe.
The standard says that all objects are initialized in the same translation unit (aka object file which corresponds to a single source file) before any function is called in that translation unit. In your example, it looks like they are in the same file, so a will be initialized before main() is called.
The standard is allowing lazy initialization to occur in the event that a DLL is loaded at run time. If you allow run-time linkage of your code, you can't say that everything is initialized before main().
Yes, if you had a object outside a function such as
Foobar foo;
If Foobar has a constructor, it would nominally run before main(). Likewise its destructor runs after main() exits. I would be hesitant to make use of this feature though. One issue, if you have these sort of objects in multiple files the order of creation is indeterminate.
In file maybe_use_foo.cpp:
namespace {
class Foo { /* ... */ };
Foo* const the_foo = new Foo;
}
void funtion_callable_from_another_tu_during_process_wide_initialization() {
// If we haven't yet run static initialization for this TU,
// but some other static initializer called us, ignore the request.
if (!the_foo)
return;
// OK, static initializers for this TU have run, foo exists, use it.
the_foo->doSomething();
}
So, independently of whether or not the above is advisable, does it always work? It seem to me that it assumes that statics are zero-initialized before the static initialization for the TU runs. Does the C++ standard (C++03? C++11?) guarantee that?
Another way to ask the question would be to ask what sequence of values, when interpreted as a Foo*, are held in the storage for 'the_foo'. Is it definitely {NULL/nullptr, new Foo}, or is it {undefined, new Foo}, or even something else?
Please don't suggest other ways of organizing: I'm not looking for suggestions on how to do this better, I'm looking for a deeper understanding of the legality of the technique.
C++11
[basic.start.init]/2
Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place.
[...]
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.
That is, yes, the variables are zero-initialized, but no, they're not zero-initialized before static initialization (but as part of static initialization).
The function in the OP will only be called during during dynamic initialization, as it is not called during zero-initialization and had to be a constexpr function to be part of constant initialization.
Yes, the C++03 standard explains in [basic.start.init]:
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place.
8.5.1 explains:
To zero-initialize an object of type T means:
— if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
[..]
Your code can cause errors. Linkers usually don't try to deeply understand initialization portions in seperate modules. Try better to provide the variable via static function, for example
namespace {
Foo* the_foo() {
static Foo* g_ = new Foo;
return g_;
}
}
Is there any guarantee that static class members are initialized before main is called?
I think no:
[C++03: 3.6.2/3]: It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized.
Hmm, really?
Well, arguably, "defined in namespace scope" is not quite the same thing as "an object of namespace scope":
[C++03: 9.4.2/2]: The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member shall appear in a namespace scope enclosing the member's class definition. In the definition at namespace scope, the name of the static data member shall be qualified by its class name using the :: operator. The initializer
expression in the definition of a static data member is in the scope of its class (3.3.6).
However, it's the initializer that's in the class's scope; there's no mention of the static member itself having anything other than namespace scope (unless we mentally inject the word "lexically" everywhere).
There is this pleasing paragraph:
[C++03: 9.4.2/7]: Static data members are initialized and destroyed exactly like non-local objects (3.6.2, 3.6.3).
However, unfortunately, the only further definition of the sequencing of main and static initialisation, with respect to "non-local objects", is the aforementioned [C++03: 3.6.2/3].
So what then?
I believe that the intent of this otherwise potentially ambiguous rule is clearly shown by the new wording in C++11, which resolves everything:
[C++11: 9.4.2/6]: Static data members are initialized and destroyed exactly like non-local variables (3.6.2, 3.6.3).
[C++11: 3.6.2/4]: It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. [..]
C++03: In short, no guarantee
C++11: No guarantee, see Lightness' answer.
My interpretation/analysis of the C++03 statements:
Terminology: [basic.start.init]/1
Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization.
Order of initialization on non-local objects:
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place.
But it doesn't mention when "any other initialization" takes place, i.e. there's no guarantee it'll be before the first statement of main, even for zero-initialization.
Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place.
But again, no guarantee.
Dynamic initialization
[basic.start.init]/3
It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized.
But what is an "object of namespace scope"? I have not found any clear definition in the Standard. scope is actually a property of a name, not of an object. Therefore we could read this as "object defined in namespace scope" or "object introduced by a name of namespace scope". Note the reference "9.4" after dynamic initialization. It refers to "Static members", which can only mean static data members. So I'd say it means "object defined at namespace scope", as static data members are defined at namespace scope:
[class.static.data]/2
The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition.
Even if you don't agree on this interpretation, there's still
[basic.start.init]/1
Objects with static storage duration defined in namespace scope in the same translation
unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit.
This clearly applies to static data members, which means that they cannot be initialized differently than objects introduced by names of namespace scope if there's such an object before the definition of the static data member. That is, if there was no guarantee at all on the dynamic initialization of static data members, the guarantees of any preceding object introduced by a name of namespace scope would apply - which are: none (it does not have to be initialized before the first statement of main).
If there's no such object preceding the definition of the static data member and you disagree on the interpretation - there would be no guarantee on the dynamic initialization of static data members at all.
Conclusion
So we only have a guarantee that dynamic initialization happens sometime (before any usage) plus an exception that initialization with side-effects must not be eliminated. Still, we have no guarantee that any kind of initialization of non-local objects is performed before the first statement of main.
Note: There are workarounds, like:
#include <iostream>
struct my_class
{
static int& my_var()
{
static int i = 42;
return i;
}
};
int j = ++my_class::my_var();
int k = ++my_class::my_var();
int main()
{
std::cout << j << " : " << k << std::endl;
}
I'd have expected the following code to yield a segmentation fault (or otherwise UB):
struct T {
T();
};
T t;
char const* str = "Test string";
T::T() {
std::cout << str; // zero-initialised, only!
}
int main() {}
That's because t is initialised before str. I'd expect str to hold the value (char const*)0 due to zero-initialisation. My interpretation of [C++11: 3.6.2/2] supports this.
However, the above snippet appears to output the string as expected (and I confirmed the behaviour by also printing the pointer's value).
Is there some rule of static initialisation that I'm missing here, that allows str to be value-initialised before t begins construction? Where is it in the standard?
This came up on static variable resolution at build time, where an answerer asserted that using char const* rather than std::string for a static global avoids the static initialisation order fiasco. I disagreed, but now I'm not so sure...
str is initialized by a constant expression and const char * is a POD type (C++03 terms, but C++11 it is analogous, but with different terms and way more allowed cases). Such an initialization is done in static initialization phase, and the static initialization phase has no issue of order. It happens before any dynamic initialization. t is initialized in the dynamic initialization phase.
Built-in types aren't initialised at all, in the normal sense. Commonly, their initial contents are memory-mapped directly from a special region of the binary as part of loading it.
I think I found it; what's happening here is not so much about the built-in type, but about the constant initialiser:
[C++11: 3.6.2/2]: Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place.
Constant initialization is performed:
if each full-expression (including implicit conversions) that appears in the initializer of a reference with static or thread storage duration is a constant expression (5.19) and the reference is bound to an lvalue designating an object with static storage duration or to a temporary (see 12.2);
if an object with static or thread storage duration is initialized by a constructor call, if the constructor is a constexpr constructor, if all constructor arguments are constant expressions (including conversions), and if, after function invocation substitution (7.1.5), every constructor call and full-expression in
the mem-initializers and in the brace-or-equal-initializers for non-static data members is a constant expression;
if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that appears in its initializer is a constant expression.
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. [..]
That final sentence would seem to override subsequent sequencing rules, making this ordering apply across Translation Units.
char const* str = "Test string";
is done by the compiler/linker, so it exists in its "initialized state" before the program even starts to run.