1

This is mainly a curiosity-driven question, I do not plan to write such code. It is a followup from my answer about dynamic initialization order.

From what I presented in the answer, inline static member variables are initialized in the order their classes appear in the source code if such order is the same across all translation units(TUs) in which they both appear.

Furthermore, section [basic.start.dynamic]-3.1 applies both to partially-ordered (other inline static) and ordered variables. That means ordinary global variables in the same TU.

So, given this example:


//A.hpp
struct A{
    inline static int a=foo();// Some function with possible side-effects
};

//B.hpp
struct B{
   inline static int b=foo();
};

//X.cpp
int x1 = foo();
#include "A.hpp"
int x2 = foo();
#include "B.hpp"
int x3 = foo();

//Y.cpp
int y1 = foo();
#include "A.hpp"
int y2 = foo();
#include "B.hpp"
int y3 = foo();

Are the variables initialized in the following order?

  1. (x1,y1) in undetermined order,
  2. a,
  3. (x2,y2) in undetermined order,
  4. b,
  5. (x3,y3) in undetermined order.

Moreover, if there are translation units with only one of the classes, does the rule still apply?

//Z.cpp
int z1 = foo(); // Initialized with (x1,y1) ?
#include "A.hpp"
int z2 = foo(); // Initialized with (x2,y2) or anytime later ?

In particular, does inclusion of A:: create a barrier which guarantees that z2 is initialized after (x1,y1)?

Results:

  • g++ 10.1.0: x1=1 a=2 x2=3 b=4 x3=5 y1=6 y2=7 y3=8 z1=9 z2=10

  • clang++ 10.0.0: a=1 b=2 x1=3 x2=4 x3=5 y1=6 y2=7 y3=8 z1=9 z2=10

Both compilers break my assumptions at least for one set of x,y variables. What am I missing? Mainly I am referencing this

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, then

Am I reading this paragraph wrongly? I am not quite sure about the ors and ands.

Quimby
  • 17,735
  • 4
  • 35
  • 55

1 Answers1

4

Let's simplify your example somewhat to make it easier to understand:

// X.cpp
int x1 = foo();
inline int a = foo();
int x2 = foo();

// Y.cpp
int y1 = foo();
inline int a = foo();
int y2 = foo();

Your question is whether x1 is guaranteed to be initialized before y2 and y1 is guaranteed to be initialized before x2.

The answer is no. As I explained in another answer the effect of the partial ordering rules for dynamic initialization is that each translation unit's "instance" of an extern inline variable is notionally treated as a separate variable; the object itself (of which there is only one) is initialized the first time any of the corresponding notional variables would be initialized.

For example, one particular ordering would do the entire X translation unit before the Y translation unit. In this case the order of initializations is x1, a, x2, y1, (no op because a was previously initialized), y2. (The compiler could likewise order everything in Y before everything in X, or interleave them.)

The quoted [basic.start.dynamic]/3.1 is from a newer edition of the standard than I was considering in my answer, but the basic logic is the same. Let V = x1 and W = y2. According to 3.1, V will be initialized before W if

V and W have ordered initialization and the definition of V is appearance-ordered before the definition of W,

"or"

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

The first condition isn't met because V isn't appearance-ordered before W. The second condition also isn't met because V and W each only have one definition, and as I said, they are not appearance-ordered.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312