为什么这个 std::launder 示例是未定义的行为?

xxh*_*hxx 8 c++

这是我不明白的示例部分:

struct Y
{
    int z;
};
int main()
{
    alignas(Y) std::byte s[sizeof(Y)];
    Y *q = new (&s) Y{2};
    const int f = reinterpret_cast<Y *>(&s)->z; // Class member access is undefined behavior:
                                                // reinterpret_cast<Y*>(&s) has value "pointer to s"
                                                // and does not point to a Y object
}
Run Code Online (Sandbox Code Playgroud)

整个示例位于https://en.cppreference.com/w/cpp/utility/launder

我不明白为什么使用reinterpret_cast<Y *>(&s)->z是未定义的行为。我们已经在所谓的“指向s的指针”处构造了一个Y对象,也将其重新解释为Y*,那为什么还说“它不指向一个Y对象”呢?

Nat*_*ica 10

&s是指向 a 的指针std::byte[sizeof(Y)],而不是 a Y。这意味着使用&sas aY*是未定义的行为,因为它违反了别名规则。即使有一个Y生活在那里,(特别是类型别名部分)的规则reinterpret_cast也不允许您访问该对象,因为它无法知道那里实际上有一个对象。

std::launder被引入是为了明确允许您将返回的指针视为指向对象的有效指针,而不是指向对象所在存储的指针。本质上,它是类型别名规则的显式覆盖。你用它告诉编译器你知道指针确实指向一个有效的对象,如果你撒谎,那么你又回到了未定义的行为领域。

  • @cmaster-reinstatemonica 不,那仍然是 UB。将对象转换为 char/byte 并读取其字节是合法的,但将存储池视为对象是非法的,除非您使用从放置 new 返回的指针,或者使用 `std::launder`。 (4认同)