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

17
std::launder函数要求通过结果可以访问的每个字节都可以通过参数访问。如果一个指向对象Y的指针值可以到达存储器中的一个字节,那么该存储器中的字节就是可到达的。如果Y是一个数组元素,则可到达的是它所占用的存储器或与Y可互换指针的对象。根据另一个问题的答案,该限制意味着“你不能使用launder获取一个指针,使你能够访问比源指针值允许的更多字节,否则会导致未定义行为。”这对于T.C.提供的例子是有道理的,但我不明白如何解释在原始对象被替换为新对象的情况下,这是std::launder最初考虑的目的。标准有以下示例:
struct X { const int n; };
X *p = new X{3};
const int a = p->n;
new (p) X{5}; // 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
  1. 我是否理解有误,或者措辞存在问题?
  2. 什么是预期的含义,使得该示例有效?

在这种情况下,当调用std::launder时,原始的X对象指向的对象p已经不存在了,因为在占用它的存储空间中创建新对象已经隐式结束其生命周期([basic.life]/1.4)。因此,似乎没有任何字节可以通过p访问,因为p没有指向任何对象Y。显然,这不是预期的解读,因为这会使示例中对std::launder的调用成为未定义的行为。


5
"Points to an out-of-lifetime object" 不等同于 "doesn't point to an object"。意思是指“指向超出其生命周期的对象”与“未指向对象”不是同一个概念。 - T.C.
我认为关键部分是“在Y占用的存储空间内”。因此,即使生命周期结束,存储空间仍然可用,并且指针可以指向它(指针值不会变为无效指针值)。 - geza
@T.C. 如果你的答案是对象在其生命周期结束后仍被认为存在于存储器中,那么你应该将其发布为答案。我无法确定C++17标准对此持何种立场——在我看来,它可能是不一致的。 - Brian Bi
不要忘记,因为指针是平凡类型,所以从技术上讲,如果有某个对象的地址,您始终可以使用“无效”指针。 - curiousguy
1个回答

1

仅就示例而言,相关文本是(加粗为本人所加):

如果一个指向对象 Y 的指针值可以访问一个字节的存储空间,那么该存储空间必须在 Y 所占用的存储空间内

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

我认为这已经足够清晰了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接