std::construct_at on top of existing object skipping re-initialization of some fields
In the following program, in a constant expression, a temporary object of A
is created with all fields initialized, and then function f
creates another object of A
at the same address, skipping (re)initialization of the field x
, which is read afterwards:
#include <memory>
struct A {
int x;
constexpr A() {}
constexpr A(int xx) : x(xx) {}
};
constexpr int f(A && a) {
std::construct_at<A>(&a);
return a.x;
}
static_assert( f(A{5}) == 5 ); //ok in GCC only
GCC accepts it just fine. But other compilers complain, e.g. Clang:
note: read of uninitialized object is not allowed in a constant expression
return a.x;
^
Demo: https://gcc.godbolt.org/z/87zrEb7q7
Indeed x
is not initialized in std::construct_at<A>(&a)
, but it was initialized in A{5}
.
Which compiler is right here?
Solution 1:
I'm convinced this is UB, and GCC is wrong.
std::construct_at<A>(&a)
creates a new A
object, and thus a new int x
member in it. That new object isn't initialized.
For this to be legal, there would have to be a special rule that uninitialized objects may get values based on the contents of memory they occupy, and I don't think such rule exists. [basic.indet]
doesn't mention it.