Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

g++ and clang++ different behaviour with recursive initialization of a static member

Given the following code:

#include <iostream>  template <std::size_t N> struct foo  { static std::size_t value; };  template <> std::size_t foo<0>::value = 0u;  template <size_t N> std::size_t foo<N>::value = 1u + foo<N - 1u>::value;  int main()  {    std::cout       << foo<3u>::value << ' '       << foo<2u>::value << ' '       << foo<1u>::value << ' '       << foo<0u>::value << std::endl;  } 

where the static member value of the template struct foo is recursively initialized, I get different outputs from g++:

3 2 1 0 

and from clang++:

1 1 1 0 

So seem that g++ initializes foo<N>::value recursively using the initialized value of foo<N-1u>::value where clang++ uses zero for foo<N-1u>::value.

Two questions:

  1. is the preceding code legit or is it Undefined Behavior in some way?
  2. if the preceding code is legit, who's right: g++ or clang++?
like image 513
max66 Avatar asked Mar 04 '19 11:03

max66


People also ask

What is the difference between normal initialization and dynamic initialization?

question. The difference between static initialization and dynamic initialization: A static initialization in java is a particular block that is made to run before the main () method in java whereas dynamic initialization refers to the initiation of the project during the rum time.

What is static and dynamic initialization in C?

Static Initialization: Here, the variable is assigned a value in advance. This variable then acts as a constant. Dynamic Initialization: Here, the variable is assigned a value at the run time. The value of this variable can be altered every time the program is being run.

What is the order of static variable initialization across one program?

C++ guarantees that variables in a compilation unit (. cpp file) are initialised in order of declaration. For number of compilation units this rule works for each one separately (I mean static variables outside of classes). But, the order of initialization of variables, is undefined across different compilation units.

How do you initialize a static member in C++?

We can put static members (Functions or Variables) in C++ classes. For the static variables, we have to initialize them after defining the class. To initialize we have to use the class name then scope resolution operator (::), then the variable name. Now we can assign some value.

How to initialize static and global variables in C++?

In C, static and global variables are initialized by the compiler itself. Therefore, they must be initialized with a constant value. Note that the above programs compile and run fine in C++, and produce the output as 10. As an exercise, predict the output of following program in both C and C++. This article is contributed by Shankar Shastri.

How are static variables handled in a recursive function?

Let us look at the tracing and see how static variables are handled in a recursive function. First, the function fun is called for the value 5 & 5 is greater than 0. Yes, so it will increment the x value i.e. x becomes 1, and then it calls itself with the reduced value of n i.e. 4, and x will be added at returning time.

Why do destructors destroy members of an object in Clang?

Modern compilers Clang, MSVC detect it with the right use of right warning flags. The reason for this language design decision is to ensure there is a unique order to destroy members; otherwise, the destructor would have to destroy objects in different orders, depending on the constructor that built the object.

Why write member initializers in the same order as their declaration?

This code harbors a bug that’s as subtly harmful as it is hard to spot hence Write member initializers in the same order as their declaration Many compilers (but not all) will issue a warning if you break this rule. Modern compilers Clang, MSVC detect it with the right use of right warning flags.


1 Answers

It is unspecified. Both compilers are right.

Here are the relevant pieces from cppreference "initialization".

Static initialization

For all other non-local static and thread-local variables, Zero initialization takes place

So for all these variables, they are zero when the program loads. Then:

Dynamic initialization

After all static initialization is completed, dynamic initialization of non-local variables occurs in the following situations:

1) Unordered dynamic initialization, which applies only to (static/thread-local) class template static data members and ... that aren't explicitly specialized.

And these variables match the criteria. And then it says:

Initialization of such static variables is indeterminately sequenced with respect to all other dynamic initialization ....

Which means that any sequence of initialization is fine. Both compilers are correct.

To avoid the issue use constexpr to force a "constant initialization" instead.

like image 152
Michael Veksler Avatar answered Sep 19 '22 14:09

Michael Veksler