Could you explain how does object definition bounds with the variable initialization, denoting initialization.
#include <iostream>
int a = 5; //definition
int main{ std::cout << a; }
sec. 1.8/1:
An object is created by a definition,[...]
a is statically initialized to 5. Initialization occurs as a part of an object definition, or it is independent from definition?
From §7/8:
A definition causes the appropriate amount of storage to be reserved and any appropriate initialization (8.5) to be done.
So yes, a definition causes initialization.
However, initialization (and object creation in general) can be caused without a definition, which is described by the omitted part of your quote (§1.8/1):
An object is created by a definition (3.1), by a new-expression (5.3.4) or
by the implementation (12.2) when needed.
An object's life time begins after its initialization has completed. It is not possible to define an object without initializing it. Even if you say int a;, you define and initialize a, although this particular kind of initialization (called "default-initialization") does nothing and leaves the object a uninitialized.
Related
It looks like we can safely use std::cout object in constructors of objects with static storage duration as stated in this question.
However, I'm not entirely sure that we can safely use them in case of variable templates:
#include <iostream>
template<class T>
T x = T{};
void foo()
{
class Test
{
public:
Test() { std::cout << "Test::Test\n"; }
};
Test t = x<Test>;
}
int main()
{
std::cout << "main\n";
}
This code crashes in clang (live example) and I'm not sure whether it's a bug or not.
As explained in that question, one effect of
#include <iostream>
is the equivalent of defining a global variable
static std::ios_base::Init __init;
which (assuming that you include it at the start of the TU) guarantees that for all static storage duration objects with ordered initialization in the same TU, the stream objects have been set up.
However, explicitly and implicitly instantiated template specializations have unordered initialization ([basic.start.dynamic]/1)1:
Dynamic initialization of a non-local variable with static storage
duration is unordered if the variable is an implicitly or explicitly
instantiated specialization, and otherwise is ordered [note omitted]. Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit.
And since
If a program starts a thread, the subsequent unordered initialization
of a variable is unsequenced with respect to every other dynamic
initialization. Otherwise, the unordered initialization of a variable
is indeterminately sequenced with respect to every other dynamic
initialization.
there's no guarantee that the stream objects have been initialized at the time the variable template specialization x<Test> is initialized.
In this case, as one of the possible executions results in undefined behavior (using the stream objects before they are initialized), the behavior of the entire program is undefined (see [intro.execution]/5).
The fix is to construct a std::ios_base::Init object yourself in Test's constructor.
1 This is actually underspecified for variable templates when C++14 was published, but it's always been the intent.
I'm getting to grips with c++ and there's one language feature I'm having particular trouble getting my head around.
I'm used to declaring and initialising a variable explicitly, but in c++ we sometimes seem to declare and implicitly construct a variable.
For example in this snippet rdev seems to be implicitly constructed (as it is subsequently used to construct a default_random_engine);
random_device rdev;
default_random_engine gen(rdev());
Can someone explain what's going on here? How can I tell this apart from a simple declaration such as int myInt; ?
Can someone explain what's going on here?
These are definitions, not just declarations. A variable definition creates the variable. In the first case, there's no initialiser, indicating that it should be default-initialised.
How can I tell this apart from a simple declaration such as int myInt; ?
That's also a definition, creating the int variable and leaving it uninitialised.
You can declare a global variable without defining it:
extern int myInt;
extern indicates that it has external linkage, and is defined somewhere else. Other kinds of variable can't be declared without defining them.
random_device rdev; // creates an instance of random_device on the stack
// with default constructor (taking no arguments)
default_random_engine gen( // creates an instance of default_random_engine
// on the stack
rdev() // passing it the result of
// invocation of operator '()'
// on the instance rdev of random_device
);
Same in a more verbose form (with some C++11):
auto rdev = random_device {};
auto gen = default_random_engine { rdev.operator()() };
Can someone explain what's going on here? How can I tell this apart
from a simple declaration such as int myInt;
They are both simple definitions.
The only difference is the properties of the type. random_device needs to be constructed, so it is. int does but people cried too much, so it isn't. Frankly, int's behaviour is more of a language defect than something you actually want.
Ultimately, this is a property of the types and not the definitions.
As stated in C++ standard (8.5.11): If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an
object with automatic or dynamic storage duration has indeterminate value. [ Note: Objects with static or
thread storage duration are zero-initialized, see 3.6.2. — end note ]
This is exactly your case: a variable definition without explicit initializer.
So, let's see what default-initialized means (8.5.7):
To default-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9),
the default constructor for T is called
(and the initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, no initialization is performed.
This clearly states the difference between your two examples:
random_device is a class type, so its default constructor (the one without arguments) is implicitly called.
int is neither a class type nor an array type, so no initialization is performed, and it will have an indeterminate value until you explicitly initialize it (by assigning a value to it).
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.
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.
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;
}