c++language-lawyerstdlaunder

How to interpret the precondition of std::launder?


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?


Solution

  • [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.