struct X { int n; };
const X *p = new const X{3}; // #1
new (const_cast<X*>(p)) const X{5}; // #2
const int c = std::launder(p)->n;
Assume that the object created at #1
is named obj1
while the object created at #2
is named obj2
. The precondition of std::launder
is that
[ptr.launder] p2 link
p represents the address A of a byte in memory. An object X that is within its lifetime and whose type is similar to T is located at the address A. All bytes of storage that would be reachable through the result are reachable through p (see below).
A byte of storage b is reachable through a pointer value that points to an object Y if there is an object Z, pointer-interconvertible with Y, such that b is within the storage occupied by Z, or the immediately-enclosing array object if Z is an array element.
This rule is a bit obscure. Is the following interpretation a right read?
obj2
will occupy the number of sizeof(X)
bytes beginning with A
. Consider Y
(the object to which std::launder(p)
points) and Z
(namely, obj2
) as the same object, they are pointer-interconvertible, and the sizeof(X)
bytes occupied by obj2
are all within Z
, hence these bytes are all reachable through std::launder(p)
. that is, "All bytes of storage that would be reachable through the result". Whether these bytes are reachable through p
? With the assumption that Y
(namely, the object to which p
points) and Z
are the same object obj1
, which are also the array element of a hypothetical array, as per [basic.compound] p3
an object of type T that is not an array element is considered to belong to an array with one element of type T.
Since these bytes beginning with A
are all within the array of which Z
is an element. Hence, we can say these bytes are all reachable through p
?
[basic.compound]/3 is not relevant. It specifically says that it applies only for the purpose of pointer arithmetic and comparison. There doesn't actually exist an array for the object.
I think when you call std::launder
, there are four objects at the relevant address: obj1
, obj1.n
, obj2
and obj2.n
.
obj1
and obj1.n
are pointer-interconvertible, as are obj2
and obj2.n
. Other combinations aside from identical pairs, are not pointer-interconvertible. There are no array objects and therefore "or the immediately-enclosing array object if Z is an array element." isn't relevant.
When considering reachability from std::launder(p)
, which points to obj2
thus only obj2
and obj2.n
need to be considered as Z
in the quote. obj2.n
occupies an (improper) subset of bytes of obj2
, so it is not relevant. The bytes reachable are those in obj2
. Except that I considered obj2.n
specifically, this is a rephrasing of your considerations.
By exactly the same reasoning, the bytes reachable from p
(pointing to obj1
) are all those in obj1
.
obj1
and obj2
have the same size and therefore occupy exactly the same bytes. Therefore std::launder(p)
would not make any bytes reachable that aren't reachable from p
.