5
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是命名的obj2。的前提std::launder

[ptr.launder] p2链接

p 表示内存中一个字节的地址 A。一个在其生命周期内且类型与 T 相似的对象 X 位于地址 A。通过结果可访问的所有存储字节都可通过 p 访问(见下文)

如果存在对象 Z,则可以通过指向对象 Y 的指针值访问存储 b 的字节,与 Y 可互转换的指针,这样 b 位于 Z 占用的存储空间内,或者如果 Z 位于立即封闭的数组对象内是一个数组元素。

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

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

不是数组元素的 T 类型对象被认为属于具有一个 T 类型元素的数组。

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

4

1 回答 1

1

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

我认为当您调用 时,std::launder相关地址有四个对象:obj1、和。 和是指针可互转换的,就像和一样。除了相同的对之外的其他组合不是指针可互转换的。没有数组对象,因此“如果 Z 是数组元素,则为立即封闭的数组对象”。不相关。obj1.nobj2obj2.nobj1obj1.nobj2obj2.n

在考虑从 的可达性时std::launder(p),仅指向obj2因此obj2并且obj2.n需要Z在引用中考虑。obj2.n占用 的(不正确的)字节子集obj2,因此不相关。可到达的字节是obj2. 除了我obj2.n特别考虑之外,这是对您的考虑的重新表述。

通过完全相同的推理,从p(指向obj1)可到达的字节都是obj1.

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

于 2022-01-17T18:18:30.697 回答