Reputation: 1841
I have the following program:
#include <iostream>
void Init();
struct Foo {
Foo() {
int *p = new int; // just to make sure Foo's ctor is not a constant expression
Init();
}
} foo;
struct Bar {
constexpr Bar()
: value(0) { }
int value;
} bar;
void Init() {
bar.value = 1;
}
int main()
{
std::cout << bar.value << std::endl;
}
Here foo
's constructor is not a constant expression, so we'll have dynamic initialization of foo
. But bar
's constructor seems to be a constant expression, so we'll have static initialization of bar
. So, bar
's ctor must be called before foo
's one and we'll see 1
as output. And I observe such result for GCC 8.3.0 and Clang 8.0.0. But for Visual C++ actual output is 0
and when I debug the application, I see that foo
's dynamic initialization is made first and then bar
's dynamic initialization is made.
Is the behavior that I observe (bar.value == 0
) valid according to C++ 17 standard?
I'm using C++ compiler version 19.16.27027.1 for x86 Debug build or Release build with ctor's marked with __declspec(noinline)
.
Upvotes: 0
Views: 1036
Reputation: 28
Probably I am late to the party, but this is a compiler bug, which also affects some portions of Boost,see https://developercommunity.visualstudio.com/t/class-with-constexpr-constructor-not-using-static/336946
This bug was fixed in: visual studio 2019 version 16.5 (March, 2020).
BTW, C++20 introduces the keyword constinit
to assert that a variable has static initialization.
Upvotes: 1
Reputation: 206577
But
bar
's constructor seems to be a constant expression, so we'll have static initialization ofbar
.
That is an incorrect uderstanding.
A constexpr
constructor can be used to construct a non-const
object too. When that happens, that object will be initialized using dynamic initialization. In your case, bar
is a non-const
object. Hence it make sense that it is initialized using dynamic initialization.
Changing your code to:
struct Bar {
constexpr Bar()
: value(0) { }
int value;
};
constexpr Bar bar;
should change initialization of bar
to static initialization.
However, if bar
is changed to a const
object, you won't be be able to use
bar.value = 1;
in Init()
. I just wanted to point out how to change bar
so it can be initialized during static initialization.
Upvotes: 5