In short: Does the following code have Undefined Behavior, or is this fine?
struct X
{
X(int b)
: value(b)
, ref(value)
{
}
int value;
int& ref;
void isThisUB() const
{
ref = 1;
}
};
int main()
{
const X x(2);
// Is either of these fine?
x.isThisUB();
x.ref = 3;
return x.value;
}
https://godbolt.org/z/1TE9a7M4a
X::value is const for x. According to my understanding of const semantics, this means that modifying it in any way is UB. Yet we can take a non-const reference to it in the constructor and then modify it through that, either in a const member function or directly.
The C++ (at least 17) standard gives an example of const-related UB in [dcl.type.cv] that looks mostly the same, except it employs const_cast. Note how p->x.j = 99 is denoted as UB. I do not see a fundamental difference between achieving this with const_cast vs my above code.
So, is the code above UB? Are non-const reference members/pointers really this big of a footgun?
(If you can come up with search keywords that yield a related question and not just random const stuff, I'll be mighty impressed.)