新放置在此指针上

时间:2018-11-10 02:10:46

标签: c++ const language-lawyer undefined-behavior placement-new

这两个打印语句打印不同的数字。据我所知,我在这里没有做任何狡猾的const_cast,所以我不确定我可以承担的UB。

  1. 此代码格式正确吗?

  2. 编译器是否可以依靠A::numconst的事实,以便允许其打印相同的数字?

代码:

struct A
{
    const int num = 100;

    A() {}    

    A(int in) : num{in} {}

    void call()
    {
        new (this) A{69};
    }
};

int main()
{
    A a;    
    std::cout << a.num << '\n';
    a.call();
    std::cout << a.num << '\n';
}

1 个答案:

答案 0 :(得分:4)

否,您的代码包含UB。删除const上的num,您将不再获得任何UB。

问题在于标准提供了保证const对象不变的保证。但是,如果您重复使用相同的存储,则可以通过某种方式“修改” const对象。

[basic.life] p8明确地禁止这样做,它说对象的旧名称在某些条件下仅引用新对象。其中之一是您的班级没有任何const成员。因此,通过扩展,您的第二个a.num是UB,因为a指的是旧的销毁对象。

但是,有两种方法可以避免此UB。首先,您可以存储指向新对象的指针:

struct A *new_ptr;
struct A {
  // [...]
  void call() {
      new_ptr = new (this) A{69};
  }
};

int main()
{
    A a;    
    std::cout << a.num << '\n';
    a.call();
    std::cout << new_ptr->num << '\n'; // ok
}

或使用std::launder

std::cout << std::launder(&a)->num << '\n'; // second access