如何解释std::launder的前置条件?

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; 

假设在 #1 创建的对象名为 obj1,而在 #2 创建的对象名为 obj2std::launder的前提是

[ptr.launder]p2link

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.

这个规则有点晦涩。以下解读是否正确?

obj2 将占用 sizeof(X)A 开头的字节数。将Ystd::launder(p)指向的对象)和Z(即obj2)视为同一个对象,它们是指针可互换的,而sizeof(X) obj2 占用的字节都在 Z 内,因此这些字节都可以通过 std::launder(p) 到达。也就是说,“通过结果可以访问的所有存储字节”。这些字节是否可以通过 p 访问?假设Y(即p指向的对象)和Z是同一个对象obj1,也是一个假想数组的数组元素,根据 [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.

因为这些以A开头的字节都在Z是一个元素的数组中。因此,我们可以说这些字节都可以通过 p?

到达

[basic.compound]/3 不相关。它特别指出它仅适用于指针运算和比较的目的。该对象实际上不存在数组。

我想当你调用std::launder时,相关地址有四个对象:obj1obj1.nobj2obj2.nobj1obj1.n 是指针可相互转换的,obj2obj2.n 也是。除了相同对之外的其他组合不是指针可相互转换的。没有数组对象,因此 " 或如果 Z 是数组元素则立即封闭的数组对象。" 不相关。

当考虑从 std::launder(p) 指向 obj2 的可达性时,因此只有 obj2obj2.n 需要在引用中被视为 Zobj2.n 占据了 obj2 的一个(不正确的)字节子集,所以它是不相关的。可访问的字节是 obj2 中的字节。除了我特别考虑 obj2.n 之外,这是对你的考虑的改写。

同理,p(指向obj1)可达的字节都是obj1.

obj1obj2 具有相同的大小,因此占用完全相同的字节。因此 std::launder(p) 不会使任何无法从 p.

访问的字节可访问