使用const成员放置new和赋值

时间:2017-11-24 12:45:35

标签: c++ const language-lawyer assignment-operator placement-new

为什么会出现这种未定义的行为?

struct s
{
    const int id; // <-- const member

    s(int id):
        id(id)
    {}

    s& operator =(const s& m) {
        return *new(this) s(m); // <-- undefined behavior?
    }
};

(从标准中引用会很好)。

这个问题来自this answer

1 个答案:

答案 0 :(得分:13)

没有什么可以使显示的代码片段本身就是UB。但是,几乎可以肯定UB会在任何正常使用情况下立即跟进。

来自[basic.life]/8(强调我的)

  

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

     
      
  • 新对象的存储空间恰好覆盖原始对象占用的存储位置,

  •   
  • 新对象与原始对象的类型相同(忽略顶级cv限定符),

  •   
  • 原始对象的类型不是const限定的,如果是类类型,不包含任何类型为const-qualified 的非静态数据成员或引用类型和

  •   
  • 原始对象是类型T的派生程度最高的对象,新对象是类型T的派生程度最高的对象(即,它们不是基类子对象)。 / p>

  •   

由于const中有s成员,因此在调用operator=后使用原始变量将为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