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.
Related
C.h:
#include <iostream>
class C {
public:
explicit C(int id) { std::cout<<"Initialized "<<id<<"\n"; }
};
1.cpp:
#include "C.h"
C global(1);
2.cpp:
#include "C.h"
thread_local C thread(2);
int main() {}
My question is: Is it guaranteed that global will be initialized before thread?
The C++ standard is somewhat vague on this point, as far as I understand it. It says (from the C++17 n4659 draft):
[basic.start.static] Static initialization
Variables with static storage duration are initialized as a
consequence of program initiation. Variables with thread storage
duration are initialized as a consequence of thread execution.
It stands to reason that "program initiation" happen before "thread execution", but since both those expressions appear in the standard only in that place, I'm seeking advise from actual language lawyers.
I'm going to use the C++20 working draft since the wording there is a little cleaner, although none of the real rules have changed.
First, thread_local behaves basically like static as far as non-local goes: [basic.stc.thread]/2:
[ Note: A variable with thread storage duration is initialized as specified in [basic.start.static], [basic.start.dynamic], and [stmt.dcl] and, if constructed, is destroyed on thread exit ([basic.start.term]). — end note ]
Yes, it's a note. But a non-local object declared thread_local is basically static so this makes sense.
Now, neither global nor thread have constant initialization - so both are zero initialized and then they have to undergo dynamic initialization. To [basic.start.dynamic]!
Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization, is partially-ordered if the variable is an inline variable that is not an implicitly or explicitly instantiated specialization, and otherwise is ordered.
Neither of our variables are specializations, neither of them are inline. So both are ordered.
A declaration D is appearance-ordered before a declaration E if
D appears in the same translation unit as E, or
the translation unit containing E has an interface dependency on the translation unit containing D,
in either case prior to E.
Our declarations are not appearance-ordered with respect to each other.
Dynamic initialization of non-local variables V and W with static storage duration are ordered as follows:
Alright, sub-bullet 1:
If V and W have ordered initialization and the definition of V is appearance-ordered before the definition of W, or if V has partially-ordered initialization, W does not have unordered initialization, and for every definition E of W there exists a definition D of V such that D is appearance-ordered before E,
Doesn't apply. It's a complicated condition, but it doesn't apply.
Otherwise, if the program starts a thread other than the main thread before either V or W is initialized, it is unspecified in which threads the initializations of V and W occur; the initializations are unsequenced if they occur in the same thread.
Nope, no threads.
Otherwise, the initializations of V and W are indeterminately sequenced.
There we go. global and thread are indeterminately sequenced.
Note also that:
It is implementation-defined whether the dynamic initialization of a non-local inline variable with static storage duration is sequenced before the first statement of main or is deferred.
and:
It is implementation-defined whether the dynamic initialization of a non-local non-inline variable with thread storage duration is sequenced before the first statement of the initial function of a thread or is deferred.
There is no guarantee and there cannot be any form of guarantee of it - at least currently.
Imagine following case, you have another unrelated static global variable Z that uses your thread_local variable during initialization or, say, even creates another thread and uses it - all during its initialization.
Now it just happens that this static global variable Z gets initialized prior to your static global variable global. This implies that the thread_local variable had to be initialized prior to your static global variable.
Note: currently, there is no way to guarantee in which order static global variables are being initialized - a known issue of C++. So if you use one global variable inside another it might or might not lead to an error - technically a UB. Don't think that it affects thread_local variables in any way as their initialization mechanism tends to be very different.
Consider the following complete program consisting of two TU's:
// 1.cpp
bool init() { /* ... */ }
const auto _{init()};
// 2.cpp
int main() {}
Question: is there any guarantee that _ is initialized at some point (I do not care when)?
Now consider the program consisting of one TU:
// 1.cpp
bool init() { /* ... */ }
const auto _{init()};
int main() {}
Note that _ is not odr-used.
However, can main(), in the second case, be said to be odr-used, since it gets (sort of) "referred by the implementation" as it gets called when the program is run?
And if main() is odr-used, does this imply that _ is guaranteed to be initialized even if it's not odr-used?
EDIT:
This is what en.cppreference.com says about Deferred dynamic initialization:
If no variable or function is odr-used from a given translation unit,
the non-local variables defined in that translation unit may never be
initialized (this models the behavior of an on-demand dynamic library)
Can you answer my questions considering the above when reading my two examples?
It's supposedly the linker's job to collate all objects with static storage-duration from all translation units for initialization during program initiation - however, its a bit more than that, the guarantee is that those objects will be initialized before the use of any function within that translation unit.
basic.start.static/1: Variables with static storage duration are initialized as a
consequence of program initiation....
Also see:
basic.stc.static/2: If a variable with static storage duration has initialization or a
destructor with side effects, it shall not be eliminated even if it
appears to be unused...
The object _ is guaranteed to be initialized. According to [basic.start.static]/1,
Variables with static storage duration are initialized as a consequence of program initiation. Variables with
thread storage duration are initialized as a consequence of thread execution.
In case you were wondering whether that could be read only as guaranteeing that static initialization shall occur, and not guaranteeing that dynamic initialization shall occur, see [dcl.dcl]/11,
A definition causes the appropriate amount of storage to be
reserved and any appropriate initialization (11.6) to be done.
Thus, all initialization required by the semantics of the initializer {init()} shall be performed on the object _.
As usual, the as-if rule applies. If init() has any observable behaviour, such behaviour must occur. It has any side effects that affect observable behaviour, such side effects must occur.
The fact that _ is not odr-used is irrelevant. The tangent about main is irrelevant too.
Does the C++ standard require that dynamic initialization of non-local static variables, be performed in the same thread that calls main()?
More specifically, in C++11, is std::this_thread::get_id() guaranteed to return the same result in static initializers and inside main()?
Edit:
Even more specifically, given the following code:
#include <iostream>
#include <thread>
static std::thread::id id = std::this_thread::get_id();
int main()
{
std::cout << id << "\n";
std::cout << std::this_thread::get_id() << "\n";
return 0;
}
are the two emitted thread IDs required/guaranteed to match?
No. The standard nowhere provides such a guarantee, and in fact the contrary is implied by [basic.start.init]/p2:
If a program starts a thread (30.3), the subsequent initialization of
a variable is unsequenced with respect to the initialization of a
variable defined in a different translation unit. Otherwise, the
initialization of a variable is indeterminately sequenced with respect
to the initialization of a variable defined in a different translation
unit. 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 would be no need to weaken the sequencing guarantee in the presence of threads if all initializations had to be performed on the same thread.
Standard doesn't say anything about what thread should perform such initialization. It only requires specific orderings and guarantees:
3.6.2 Initialization of non-local variables [basic.start.init]
2. Static initialization shall be performed before any dynamic initialization takes place. [...] Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. [...] If a program starts a thread, the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit.
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. If the initialization is deferred to some point in time
after the first statement of main, it shall occur before the first odr-use of any function or variable defined in the same translation unit as the variable to be initialized.
5. It is implementation-defined whether the dynamic initialization of a non-local variable with static or thread storage duration is done before the first statement of the initial function of the thread. If the initialization is deferred to some point in time after the first statement of the initial function of the thread, it shall occur before the first odr-use of any variable with thread storage duration defined in the same translation unit as the variable to be initialized.
However, most implementations will do so - initialization of static non-local variables will be performed in the same thread, that calls main(). Example from Visual C++ 11:
#include <iostream>
#include <thread>
using namespace std;
struct Cx
{
public:
Cx()
{
cout<<"Cx: "<<std::this_thread::get_id()<<endl;
}
};
static Cx c;
int main()
{
cout<<"Main: "<<std::this_thread::get_id()<<endl;
return 0;
}
Output:
Cx: 5820
Main: 5820
After setting breakpoint inside Cx::Cx():
No, though it may be a good idea to write your program that way. The syntax requires that static initialization happens in a deterministic way, but does not dictate things like the thread involved.
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.
I have a program split up into two source files:
example.cpp
#include <iostream>
class A {
public:
A(int x) {
::std::cout << "In A(" << x << ")\n";
}
};
static A first(1);
static A second(2);
example__main.cpp
int main(int argc, const char *argv[])
{
return 0;
}
Is the output of this program guaranteed to be:
In A(1)
In A(2)
on all platforms and compilers? If so, where in the standard does it say this? Does it matter if I'm using namespaces and first and second appear in different namespaces? How about if they aren't static and I'm using an anonymous namespace?
Yes, the order of initialization is defined for non-local static objects if the declarations appear in the same translation unit.
From C++03,
(3.6/2) 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. [Note: 8.5.1 describes the order in which aggregate members are
initialized. The initial-ization of local static objects is described
in 6.7. ]
Within one translation unit, global variables are initialized in several stages:
First, all variables that have "static initialization" are initialized in their order of declaration (see below).
Then, all "ordered dynamic initializations" are performed, again in their order of declaration.
There are also "unordered dynamic initializations", which are "unsequenced" with respect to the other dynamic initializations (but always after the static ones).
Destruction of statically and ordered-dynamically initialized globals proceeds in opposite order (and the unordered ones again "unsequenced", but before the static ones). The relative initialization ordering across TUs is unspecified.
To explain the terminology loosely: a global variable is "statically initialized" if it is either initialized to a constant (for constructor calls, this requires constexpr constructors), or if it is has no initializer and is declared static (which makes it zero-initialized): static int a; Foo b(1, true, Blue); On the other hand, if the initializer is not anything "constant", like a function call or a non-constexpr constructor, then the object is "dynamically initialized". Most ordinary globals that are dynamically initialized are "ordered"; the only "unordered" ones are static members of template specializations and such like.
(Note that all this got a lot more detailed in C++11, as there is now explicit attention to thread-local storage and initialization at the start of a thread.)