交换 const 成员是未定义的行为吗? C++17

Is swapping a const member undefined behavior? C++17

https://godbolt.org/z/E3ETx8a88

这是换UB吗?我在改变什么吗? UBSAN 没有报告任何东西。

#include <utility>

struct MyInt
{
    MyInt(int ii): i(ii) {}
    const int i;
    MyInt& operator=(MyInt&& rh)
    {
        std::swap(const_cast<int&>(i), const_cast<int&>(rh.i));
        return *this;
    }
};

int main() {
    MyInt i0(0);
    MyInt i2(2);

    i0 = std::move(i2);
    return i0.i;
}

Is this swapping UB?

是的,这是UB。

Am I mutating anything?

您正在改变 const 对象。这是不允许的。

来自const_cast

Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue results in undefined behavior.

所以对,就是UB

这似乎是 c++ 进化的一个领域。

由于this restriction on replacing const member objects

,它在 c++17 中是 UB

但是,在以后的版本中,this restriction is mostly removed.。对完整的 const 对象仍然存在限制。例如,如果 MyInt i0(0);const MyInt i0(0);

,则不能这样做

尽管 c++20 现在允许修改 const 子对象,但最好避免 const_cast 并使用它来创建赋值构造函数。在这种情况下,不需要析构函数,因为它很容易被破坏。请注意,在 c++20 之前必须使用 placement new 并且仍然是 UB,因为以前不允许更改 const 子对象。

constexpr MyInt& operator=(MyInt&& rh)
{
    std::construct_at(&this->i, rh.i);
    return *this;
}