1

I was reading thru Dynamic Initialization but not able to understand completely as examples are missing of what is Unordered dynamic initialization, Partially-ordered dynamic initialization and Ordered dynamic initialization?

Can anyone please provide same - this will give more clarity to theory?

Programmer
  • 8,303
  • 23
  • 78
  • 162

1 Answers1

2

Dynamic initialization

Dynamic initialization concerns non-local variables that are not initialized with constexpr expresssions.

int foo();
int global = foo();

As cppreference explains in quite some details, the compiler has some leeway and can either schedule dynamic initialization with the static one or deffer it as long as it will not change the behavior of the program.

Please treat all initialization with =foo() as intendent to be dynamic with enough side-effects to create UB for unordered initialization. E.g.:

int foo(){//Pretend to be flexible on the return type
   static int i =0;
   return ++i;
}

The following behaviour is governed by [basic.start.dynamic], from now on referred as rules:

  • 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.

    [Note: An explicitly specialized non-inline static data member or variable template specialization has ordered initialization. — end note]

  • 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.
  • Dynamic initialization of non-local variables V and W with static storage duration are ordered as follows:

    • 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
      • if the program does not start a thread ([intro.multithread]) other than the main thread ([basic.start.main]) or V and W have ordered initialization and they are defined in the same translation unit, the initialization of V is sequenced before the initialization of W;
      • otherwise, the initialization of V strongly happens before the initialization of W.
    • 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.
    • Otherwise, the initializations of V and W are indeterminately sequenced.
  • [Note: This definition permits initialization of a sequence of ordered variables concurrently with another sequence. — end note] ... The rest of the section deals with sequencing the initialization with the main and other threads.

Unordered dynamic initialization

The first rule is relevant. Note that explicitly instantiated specialization is different from explicit specialization:


template<typename T>
struct A{
    static int x = foo();
}
// Rules are the same as for non-templates
template<>
struct A<char>{
    //C++17 inline definition
    inline static int x = foo();
    // Only declaration, must be defined in some translation unit
    static int y;
}

//Explicit instantion of `A` class template's `double` specialization.
template class A<double>;

tempalte<> struct A<char>::y=foo();
int main(){
    // Implicit instantiation of `A` class template's `int` specialization.
    A<int> v1;

    // Implicit instantiation of `A` class template's explicit `int` specialization.
    A<char> va2;
}

Order:

  • A<int>::x, A<double>::x, A<char>::y are unordered with respect to all other dynamic initialization, including themselves.
  • A<char>::y is ordered with other ordered variables in the same translation unit it is defined in. It is NOT ordered w.r.t the ^ three variables (because they are unordered).

The same rules are for variable templates.

Partially ordered initialization

The first rule says the partial order applies to C++17 inline static variables in non-templated classes. The second and third rules define the order. Cppreference summs it up pretty nicely.

[Side note C++17 inline attribute for static member variables allows to define and initialize the variables immediately in the class definition and not require the programmer to pick a favourite translation unit(.cpp) in which they would have to place the definition separately. This lead to countless SO questions where the author forgot to do just that. Originally, it was this way to enforce One Definition Rul, but the example above already allows to "break" it with templates. In this case, the compiler must define the A<T>::x correctly, no matter in how many TUs is A<T> instantiated for the same T. Hence C++17 allows the same "violation" for non-templates. It is the responsibility of the compiler (rather linker though) to deal with more than one source-code-identical inline static member variable definition. ]

Let's have this example:

class B{
   inline static int b = foo();
};
class C{
   inline static int c = foo();
};

The initialization of a,b is ordered only if in all translation units where both class definitions appear, they appear in the same order.

Furthermore, the third rule establishes the order with other ordered variables as the same order in which they appear in the source code:

#include "B.h"

static int global = foo();

#include "C.h"

If there are multiple TUs with such structure, the order of initialization should be:

  1. B::b
  2. All global variables in undefined order.
  3. C::c

Thinking about it, I believe this forces a C++ compiler to create a directed graph with "appear before" relationship, check if it has topological ordering and initialize the variables in such ordering.

Ordered initialization

Applies to all other non-local variables:

  1. non-inline static members,
  2. "ordinary" global static variables.

I.e. exactly the variables governed by ODR meaning the initialization must appear only in one translation unit.

  • They are initialized w.r.t to other varibles in the same TU exactly in the order they appear in the source code.
  • They are unordered w.r.t to variables from other TUs.
Quimby
  • 17,735
  • 4
  • 35
  • 55