Your code invokes UB, but not for launder
reasons. It's because p0[1].i
is itself UB.
Yes, really ([Expr.Add]/4):
When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression P points to element x[i] of an array object x with n elements, the expressions P + J and J + P (where J has the value j ) point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤ n ; otherwise, the behavior is undefined. Likewise, the expression P - J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j ≤ n; otherwise, the behavior is undefined.
An object that is not an array element is considered to belong to a single-element array for this purpose; see 8.3.1. A pointer past the last element of an array x of n elements is considered to be equivalent to a pointer to a hypothetical element x[n] for this purpose; see 6.9.2.
[]
when applied to a pointer means to do pointer arithmetic. And in the C++ object model, pointer arithmetic can only be used on pointers to elements in an array of the type being pointed to. You can always treat an object as an array of length 1, so you can get a pointer to "one past the end" of the single object. Thus, p0 + 1
is valid.
What is not valid is accessing the object stored at that address though the pointer obtained via p0 + 1
. That is, p0[1].i
is undefined behavior. This is just as UB before laundering it as after.
Now, let's look at a different possibility:
X x[2];
x[1].~X(); //Destroy this object.
new(x + 1) X; //Construct a new one.
So let's ask some questions:
Is x[1]
UB? I would say... no, it is not UB. Why? Because x[1]
is not:
a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object
x
points to the array and the first element of that array, not the second element. Therefore, it does not point to the original object. It is not a reference, nor is it the name of that object.
Therefore, it does not qualify for the restrictions stated by [basic.life]/8. So x[1]
should point to the newly constructed object.
Given that, you don't need launder
at all.
So if you're doing this in a way that's legal, then you don't need launder
here.