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

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

问题描述

为什么这种不确定的行为?

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

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