https://godbolt.org/z/E3ETx8a88
Is this swapping UB? Am I mutating anything? UBSAN does not report anything.
#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;
}
CodePudding user response:
Is this swapping UB?
Yes, this is UB.
Am I mutating anything?
You are mutating const objects. That's not allowed.
CodePudding user response:
This seems to be an area of c evolution.
It's UB in c 17 because of this restriction on replacing const member objects
However, in later versions, this restriction is mostly removed.. There remains a restriction on complete const objects. For instance you can't do this if MyInt i0(0);
was const MyInt i0(0);
Even though c 20 now allows modification of const sub objects, it's best to avoid const_cast
and use this to create an assignment ctor. In this case one doesn't need a destructor since it's trivially destructable. Note that one had to use placement new prior to c 20 and that was still UB since const sub objects were not permitted to change previously.
constexpr MyInt& operator=(MyInt&& rh)
{
std::construct_at(&this->i, rh.i);
return *this;
}
CodePudding user response:
From 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.
so Yes, that is UB.