如何解释 std::launder 的可达性要求?

Posted

技术标签:

【中文标题】如何解释 std::launder 的可达性要求?【英文标题】:How to interpret the reachability requirement of std::launder? 【发布时间】:2019-12-19 06:50:49 【问题描述】:

std::launder 函数要求可以通过结果访问的每个字节都可以通过参数访问。 “可达”定义如下:

一个字节的存储空间可以通过一个指向对象Y的指针值来访问,如果它在Y占用的存储空间内,一个对象是 与 Y 可相互转换的指针,如果 Y 是数组元素,则为直接封闭的数组对象。

根据an answer 的另一个问题,此限制“...意味着您不能使用launder 来获取一个指针,该指针允许您访问比源指针值允许的更多字节,因为未定义行为的痛苦。”

这对于 T.C. 给出的示例是有意义的。但我不明白在原始对象已被新对象替换的情况下如何解释它,这是std::launder 的原始目的。该标准有以下示例:

struct X  const int n; ;
X *p = new X3;
const int a = p->n;
new (p) X5; // p does not point to new object (6.8) because X::n is const
const int b = p->n; // undefined behavior
const int c = std::launder(p)->n; // OK

在这种情况下,在调用std::launder 时,p 指向的对象---原来的X 对象---自从在它占用的存储空间已隐式结束其生命周期([basic.life]/1.4)。因此,似乎没有可通过p 到达的字节,因为p 不指向任何对象Y。这显然不是预期的阅读内容,因为它会调用示例中的 std::launder 未定义行为。

    是我误解了这里的措辞,还是措辞有缺陷? 预期的含义是什么,这将使示例有效?

【问题讨论】:

"指向过期对象" != "不指向对象"。 我认为关键部分是within the storage occupied by Y。所以即使生命周期结束,存储也是可用的,并且指针可以指向它(指针值不会变成无效的指针值)。 @T.C.如果您的答案是对象在其生命周期结束后仍被认为存在于存储中,您应该将其发布为答案。我无法弄清楚 C++17 标准对此采取了什么立场——在我看来,这可能是不一致的。 不要忘记,因为 ptr 是普通类型,从技术上讲,如果存在某个地址的对象,您始终可以使用“无效”ptr。 【参考方案1】:

举个例子,相关的文字是(粗体是我的):

一个字节的存储可以通过一个指向的指针值来访问 一个对象 Y,如果它在 Y 占用的存储空间内

由于 placement new,指针值现在指向“新放置的”对象,因此可达性就是那个。

我想说这已经足够清楚了。

【讨论】:

以上是关于如何解释 std::launder 的可达性要求?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这里需要 std::launder ?

为啥要引入 `std::launder` 而不是让编译器处理它?

我在哪里可以找到 std::launder 的真正作用? [复制]

std::launder 替代 pre c++17

带有就地多态容器的 std::launder

std::launder 的效果是不是在调用它的表达式之后持续?