为什么要引入 `std::launder` 而不是让编译器来处理呢?

Why introduce `std::launder` rather than have the compiler take care of it?

我刚读完

坦率地说,我摸不着头脑。

让我们从@NicolBolas 接受的答案中的第二个例子开始:

aligned_storage<sizeof(int), alignof(int)>::type data; 
new(&data) int; 
int *p = std::launder(reinterpret_cast<int*>(&data)); 

[basic.life]/8 tells us that, if you allocate a new object in the storage of the old one, you cannot access the new object through pointers to the old. std::launder allows us to side-step that.

那么,为什么不直接更改语言标准,以便通过 reinterpret_cast<int*>(&data) 访问 data 是 valid/appropriate?在现实生活中,洗钱是一种向法律隐瞒现实的方式。但我们没有什么可隐瞒的——我们正在做一些完全合法的事情。那么,当编译器注意到我们正在以这种方式访问​​ data 时,为什么它不能将其行为更改为 std::launder() 行为呢?

第一个例子:

X *p = new (&u.x) X {2};

Because X is trivial, we need not destroy the old object before creating a new one in its place, so this is perfectly legal code. The new object will have its n member be 2.

So tell me... what will u.x.n return?

The obvious answer will be 2. But that's wrong, because the compiler is allowed to assume that a truly const variable (not merely a const&, but an object variable declared const) will never change. But we just changed it.

那为什么不让编译器允许我们在写这种代码时,通过指针访问常量域的假设呢?

为什么使用这个伪函数来打孔形式语言语义是合理的,而不是根据代码是否执行这些示例中的操作来将语义设置为它们需要的内容?

depending on whether or not the code does something like in these examples

因为编译器无法始终知道何时“以这种方式”访问 data

按照目前的情况,允许编译器假设以下代码:

struct foo{ int const x; };

void some_func(foo*);

int bar() {
    foo f { 123 };
    some_func(&f);
    return f.x;
}

bar 将始终 return 123。编译器 可能 生成实际访问对象的代码。但是对象模型并不要求这个。 f.x 是一个 const 对象(不是 reference/pointer 到 const),因此无法更改。并且 f 需要始终命名相同的对象(实际上,这些是您必须更改的标准部分)。因此,f.x 的值不能通过任何非 UB 方式更改。

Why is it reasonable to have this pseudo-function for punching a hole in formal language semantics

这是 actually discussed。该论文提出了这些问题存在了多长时间(即:自 C++03 以来),并且通常采用了由该对象模型实现的优化。

该提议被拒绝,理由是它实际上不能解决问题。来自 this trip report:

However, during discussion it came to light that the proposed alternative would not handle all affected scenarios (particularly scenarios where vtable pointers are in play), and it did not gain consensus.

该报告没有详细说明此事,相关讨论也未公开。但该提案本身确实指出,它不允许将 second 虚函数调用去虚拟化,因为第一个调用可能已经构建了一个新对象。所以即使是 P0532 也不会让 launder 变得不必要,只是没那么必要了。