Given a static member variable which is initialized from a static member variable of another class, the non-literal struct ii
is sometimes default init
Congratulations! You've encountered the static initialization order fiasco.
The initialization order of static objects is not defined across multiple translation units.
StaticClass::ii
is defined in ONE.cpp
and ABC::def_ii
is defined in abc.cpp
. Therefore StaticClass::ii
may or may not be initialized before ABC::def_ii
. Since the initialization of ABC::def_ii
uses the value of StaticClass::ii
the value will depend on whether StaticClass::ii
was initialized yet†.
The initialization order of static objects within a translation unit is defined. Objects are initialized in the order in which they are defined. Therefore when you concatenate the source files, the order of initialization is defined. However, when you concatenate the files in the wrong order, the defined initialization order is wrong:
const OneI ABC::def_ii = StaticClass::ii; // StaticClass::ii wasn't initialized yet
const OneI StaticClass::ii = OneI{333};
Can this be avoided somehow by enforcing the latter ordering all the time?
Most trivial solution is to define both objects in the same translation unit, in the correct order. A more general solution is to initialize your static objects using Construct On First Use Idiom.
Is using a static pointer in
ABC
toStaticClass::ii
safe (I'd prefer not to, though)?
As long as the dereferenced value of the pointer isn't used during the initialization of a static object in another translation unit that where the pointed object is defined, yes, replacing ABC::def_ii
with a pointer would be safe.
† StaticClass::ii
will have been zero-initialized during the static initialization phase††. The Static initialization order fiasco concerns the dynamic initialization phase††.
†† C++ standard draft [basic.start.static]
If constant initialization is not performed, a variable with static storage duration ([basic.stc.static]) or thread storage duration ([basic.stc.thread]) is zero-initialized ([dcl.init]). 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. [ 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 ]