std::launder 可达性

reachability with std::launder

我正在尝试理解 CPP reference 中的以下片段。有人可以更详细地解释为什么 x2[1] 无法从 source 访问吗?例如,我们不能通过 &x2[0][0] + 10 到达它吗?

int x2[2][10];
auto p2 = std::launder(reinterpret_cast<int(*)[10]>(&x2[0][0])); 
// Undefined behavior: x2[1] would be reachable through the resulting pointer to x2[0]
// but is not reachable from the source

可达性条件基本上询问是否可以通过指针算法访问给定的内存字节和从给定指针 reinterpret_cast 。在链接的 cppreference 页面上给出了实际上相同的技术定义:

(bytes are reachable through a pointer that points to an object Y if those bytes are within the storage of an object Z that is pointer-interconvertible with Y, or within the immediately enclosing array of which Z is an element)

x2 是 2 个数组 10 数组 int 的数组。假设我们调用两个数组 ab.

&x2[0][0] 是指向 a 的第一个元素的 int*

&x2[0][0] + 10 是一个 int* 指针 one-past 最后一个元素 a。这个指针值的地址也是b开始的地址。但是,无法通过 reinterpret_cast 获得指向 b 或其元素之一的指针,因为 &x2[0][0] + 10 不指向 pointer-interconvertible 和 b 的任何对象或它的元素之一。

在技术定义上,第一个元素为a的唯一对象pointer-interconvertible就是对象本身。因此,从指向 a 的第一个元素的指针的可到达字节只是 a 的字节,它是 立即 包含此对象的数组。

因此通过&x2[0][0]可达的字节只是数组a的字节,不包括b。例如。 *(&x2[0][0] + 10) = 123; 有未定义的行为。

然而,如果 std::launder 指向 return 指向 a 的指针(int(*)[10] 类型),那么 (p2+1)[i] 将是一种访问所有b 的元素。或者按照技术定义, immediately 包围对象 p2 指向的数组将是 x2,因此 x2 的所有字节都是可达。

这意味着之前无法访问的 std::launder 字节将变得可以访问。因此调用具有未定义的行为。