使用const成员放置new和赋值

DaB*_*ler 10 c++ const placement-new assignment-operator language-lawyer

为什么这种未定义的行为?

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

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

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

(从标准引用会很好).

这个问题来自于这个答案.

Pas*_* By 16

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

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

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

  • 新对象的存储完全覆盖原始对象占用的存储位置,以及

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

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

  • 原始对象是类型最派生的对象,T新对象是类型最派生的对象T(也就是说,它们不是基类子对象).

由于有一个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
Run Code Online (Sandbox Code Playgroud)

  • 这个答案可能不再正确,因为引用的句子在 C++20 中被放宽:https://github.com/cplusplus/draft/commit/fd8ff6441f93024bd0ee6e03a03c08be8e1b5ce0 (3认同)
  • @DaBler从技术上讲,有。但我强烈建议您反对。`auto&ref =(var = s {420});`。然后使用`ref` (2认同)