我刚读过
坦率地说,我只能摸不着头脑。
让我们从@NicolBolas 接受的答案中的第二个示例开始:
aligned_storage<sizeof(int), alignof(int)>::type data; new(&data) int; int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life]/8 告诉我们,如果在旧对象的存储中分配新对象,则无法通过指向旧对象的指针访问新对象。
std::launder
允许我们回避这一点。
那么,为什么不直接更改语言标准,以便data
通过 a进行访问reinterpret_cast<int*>(&data)
是有效/适当的呢?在现实生活中,洗钱是向法律隐瞒现实的一种方式。但我们没有什么可隐瞒的——我们在这里做的是完全合法的事情。std::launder()
那么,当编译器注意到我们正在data
以这种方式访问时,为什么不能将其行为更改为它的行为呢?
上第一个例子:
X *p = new (&u.x) X {2};
因为 X 是微不足道的,我们不需要在创建一个新对象之前销毁旧对象,所以这是完全合法的代码。新对象的 n 成员将为 2。
所以告诉我...什么会
u.x.n
返回?显而易见的答案是 2。但这是错误的,因为允许编译器假设一个真正的
const
变量(不仅仅是一个 const&,而是一个声明的对象变量const
)永远不会改变。但我们只是改变了它。
那么为什么不让编译器在我们编写这种代码时不允许做出假设,通过指针访问常量字段呢?
为什么让这个伪函数在形式语言语义上打一个洞是合理的,而不是根据代码是否像这些示例中那样将语义设置为它们需要的语义?