问题描述
为什么这种不确定的行为?
Why is that undefined behaviour?
struct s
{
const int id; // <-- const member
s(int id):
id(id)
{}
s& operator =(const s& m) {
return *new(this) s(m); // <-- undefined behavior?
}
};
(引用标准会很好).
此问题来自此答案.
推荐答案
没有什么可以使所显示的代码段本质上成为UB.但是,几乎可以确定,在任何正常使用情况下,UB都会立即出现.
There is nothing that makes the shown code snippet inherently UB. However, it is almost certain UB will follow immediately under any normal usage.
来自 [basic.life]/8 (重点是我)
-
新对象的存储空间正好覆盖了原始对象所占据的存储位置,并且
the storage for the new object exactly overlays the storage location which the original object occupied, and
新对象与原始对象具有相同的类型(忽略顶级cv限定词),并且
the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
原始对象的类型不是const限定的,并且,如果是类类型,不包含任何类型为const限定的非静态数据成员类型,然后
the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
原始对象是T
类型的最大派生对象,而新对象是T
类型的最大派生对象(也就是说,它们不是基类的子对象).
the original object was a most derived object of type T
and the new object is a most derived object of type T
(that is, they are not base class subobjects).
由于s
中有一个const
成员,因此在调用operator=
后使用原始变量将是UB.
Since there is a const
member in s
, using the original variable after a call to operator=
will be UB.
s var{42};
var = s{420}; // OK
do_something(var.id); // UB! Reuses s through original name
do_something(std::launder(&var)->id); // OK, this is what launder is used for
这篇关于使用const成员进行新的放置和类分配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!