This question results from thinking about my answer in Given two objects of different types and their relative location in memory, can I derive a pointer to one object from a pointer to the other?.
My assumption was that the standard currently allows, under the assumption that sizeof(int) == sizeof(float)
, alignof(int) == alignof(float)
and sizeof(int) == alignof(int)
, to optimize the function g
in
void f(float*);
int g() {
alignas(int) std::byte storage[sizeof(int)*2];
auto x = new(storage) float();
auto y = new(storage + sizeof(float)) int();
f(x);
return *y;
}
to always return 0
, because it is impossible to reach the int
object from the float
object due to the reachability precondition on std::launder
. As far as I can tell no current compiler actually does this though.
However, suppose f
was defined like this:
struct A {
float x;
int y;
};
void f(float* x) {
reinterpret_cast<A*>(x)->y = 1;
}
assuming sizeof(A) == 2*sizeof(int)
and alignof(A) == alignof(int)
on the implementation.
Doesn't f
then have well-defined behavior, so that the optimization is impossible, because implicit object creation when the lifetime of storage
begins can create an A
object of which the int
and float
objects would become member subobjects and for which the float
object is pointer-interconvertible with the A
object?
Am I misunderstanding the intended optimization benefit of the std::launder
reachability precondition or is implicit object creation from C++20 just messing it up? Is it supposed to apply only to non-standard-layout types?
Also see my related question std::launder vs placement-new reachability condition.
int
s, because in some TU there can be a type having them as member subobjects. I think your example is somewhat similar. – Infarction