lundi 20 septembre 2021

Contradictory definitions about the Order of Constant Initialization and Zero Initialization in C++

I have been trying to understand how static variables are initialized. And noted a contradiction about the order of constant initialization and zero initialization at cppref and enseignement.

At cppref it says:

Constant initialization is performed instead of zero initialization of the static and thread-local (since C++11) objects and before all other initialization.

Whereas at enseignement it says:

Constant initialization is performed after zero initialization of the static and thread-local objects and before all other initialization.

So as you can see cppref uses "instead" while the second site uses "after". Which of the two is correct? That is, does zero initialization always happen first and then if possible constant initialization as implied by the second site or the other way round.

The example given there is as follows:

#include <iostream>
#include <array>
 
struct S {
    static const int c;
};
const int d = 10 * S::c; // not a constant expression: S::c has no preceding
                         // initializer, this initialization happens after const
const int S::c = 5;      // constant initialization, guaranteed to happen first
int main()
{
    std::cout << "d = " << d << '\n';
    std::array<int, S::c> a1; // OK: S::c is a constant expression
//  std::array<int, d> a2;    // error: d is not a constant expression
}

This is my understanding of the initialization process so far:

  1. Static initialization happens first. This includes
  • Constant initialization if possible
  • Zero initialization only if constant initialization was not done
  1. Dynamic Initialization

Now according to the above(my understanding) this is how the code above works:

Step 1.

When the control flow reaches the definition of const int d it sees that the initializer has a variable(namely S::c) that has not been already initialized. So the statement const int d = 10 * S::c; is a dynamic time(runtime) initialization. This means it can only happen after static initialization. And ofcourse d is not a constant expression.

Step 2.

The control flow reaches the definition of variable const int S::c; . In this case however the initializer is a constant expression and so constant initialization can happen. And there is no need for zero initialization.

Step 3.

But note that we(the compiler) still haven't initialized the variable d because it left its initialization because it has to be done dynamically. So now this will take place and d will get value 50. But note d still isn't a constant expression and hence we cannot use it where a constant expression is required.

Is my analysis/understanding of the concept correct and the code behaves as described?

Note:

The order of constant initialization and zero initialization is also different at cppref-init and enseignement-init.

Aucun commentaire:

Enregistrer un commentaire