使用 const 成员放置 new 和分配类 [英] Placement new and assignment of class with const member

查看:31
本文介绍了使用 const 成员放置 new 和分配类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么是未定义的行为?

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(重点是我的)

如果在一个对象的生命周期结束后,在该对象占用的存储空间被重用或释放之前,在原对象占用的存储位置创建一个新对象,一个指向原对象的指针,引用原始对象的引用或原始对象的名称将自动引用新对象,并且一旦新对象的生命周期开始,可用于操作新对象,如果:

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:

  • 新对象的存储正好覆盖了原始对象所占用的存储位置,并且

  • 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 成员放置 new 和分配类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆