这两个打印语句打印不同的数字。据我所知,我在这里没有做任何狡猾的const_cast
,所以我不确定我可以承担的UB。
此代码格式正确吗?
编译器是否可以依靠A::num
是const
的事实,以便允许其打印相同的数字?
代码:
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';
}
答案 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