Consider this union:
union A{
int a;
struct{
int b;
} c;
};
c
and a
are not layout-compatibles types so it is not possible to read the value of b
through a
:
A x;
x.c.b=10;
x.a+x.a; //undefined behaviour (UB)
For Trial 1 and Trial 2 see this question
Trial 3
Now let's use std::launder
for what it does not seems to be intended:
A x;
x.a=10;
auto p = &x.a; //(1)
x.c.b=12; //(2)
p = std::launder(p); //(2')
*p+*p; //(3) UB?
Could std::launder
change anything? According to [ptr.launder]:
template <class T> constexpr T* launder(T* p) noexcept;
Requires:
p
represents the address A of a byte in memory. An object X that is within its lifetime and whose type is similar toT
is located at the address A. All bytes of storage that would be reachable through the result are reachable throughp
(see below).Returns: A value of type
T *
that points to X.Remarks: An invocation of this function may be used in a core constant expression whenever the value of its argument may be used in a core constant expression. A byte of storage is reachable through a pointer value that points to an object Y if it is within the storage occupied by Y, an object that is pointer-interconvertible with Y, or the immediately-enclosing array object if Y is an array element. The program is ill-formed if T is a function type or cv void.
The bolded sentence emphasizes a someting that troubles me. If p
is an invalid pointer value, how could any byte of storage be accessible? On the other hand with such a reading std::launder
is just not usable.
Otherwise, could p
's value at (2) be a pointer value that represents a region of storage as is talked about in a "Note" in [basic.life]:
If these conditions are not met, a pointer to the new object can be obtained from a pointer that represents the address of its storage by calling
std::launder
([support.dynamic]).