Consider the following code, split across three compilation units:
a.h:
struct A
{
void Register(const char* s);
const char* m_s[10];
int m_i = 0;
};
A& GetA();
a.cpp:
#include "a.h"
#include <stdio.h>
void A::Register(const char* s)
{
m_s[m_i++] = s;
}
A& GetA()
{
static A instance;
return instance;
}
int main(int argc, char* argv[])
{
A& a = GetA();
int n = a.m_i;
for (int i = 0; i < n ; ++i)
printf("%s\n", a.m_s[i]);
return 0;
}
b.cpp:
#include "a.h"
struct B
{
B() { GetA().Register("b"); }
static B* instance;
};
B* B::instance = new B;
c.cpp:
#include "a.h"
struct C
{
C() { GetA().Register("c"); }
static C* instance;
};
C* C::instance = new C;
The code builds and runs fine using gcc (-std=c++11), producing the output:
c
b
Now, referring to cppreference.com:
Deferred dynamic initialization
It is implementation-defined whether dynamic initialization happens-before the first statement of the main function (for statics) or the initial function of the thread (for thread-locals), or deferred to happen after.
If the initialization of a non-inline variable is deferred to happen after the first statement of main/thread function, it happens before the first odr-use of any variable with static/thread storage duration defined in the same translation unit as the variable to be initialized. 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). However, as long as anything from a TU is odr-used, all non-local variables whose initialization or destruction has side effects will be initialized even if they are not used in the program.
Note that a.cpp is unaware of the existence of B and C, and that the only interactions of B & C with A are the invocations of GetA() and A::Register() during construction of their respective instances.
As far as I can see, the B & C instances are not ODR-used, and certainly not from main()'s translation unit. Their initialisation clearly has side effects, so I can understand that they will be initialised at some stage. But it seems to me that there's no guarantee that this initialisation will occur before entry to main() - no guarantee, even, that they will be initialised before main() prints the registered strings.
So - finally - my question is this: Is the fact that the B and C instances are initialised before main() prints the registered strings due not to the standard, but instead to gcc's implementation-defined behaviour?
If it is guaranteed by the standard, how?
Aucun commentaire:
Enregistrer un commentaire