dcl.type.cv provides an interesting example:
For another example,
struct X { mutable int i; int j; }; struct Y { X x; Y(); }; const Y y; y.x.i++; // well-formed: mutable member can be modified y.x.j++; // ill-formed: const-qualified member modified Y* p = const_cast<Y*>(&y); // cast away const-ness of y p->x.i = 99; // well-formed: mutable member can be modified p->x.j = 99; // undefined: modifies a const member
which indicates that, via const_cast
, one may modify mutable
members of a const
qualified object, while you can't do that with non-mutable
members.
To my understanding, this is because of the original const
ness of y
itself. What would happen if we got rid of the mutable
keyword, the const
qualifier fot y
, but modified the fields in a const
method?
Example below:
#include <vector>
struct foo {
std::vector<int> vec{};
void bar() const {
auto& raw_ref = const_cast<std::vector<int>&>(vec);
raw_ref.push_back(0); // ok?
auto* raw_this = const_cast<foo*>(this);
raw_this->vec.push_back(0); // ok?
}
};
int main() {
foo f{};
f.bar();
}
Does it exhibit Undefined Behaviour? I would think that it does not, since we're modifying an originally non-const
, but in a const
context.
Additionally, notice that I provided two ways of modifying the vec
. One with non-const
reference and one with non-const
pointer to this
(which was originally const
in this constext due to foo::bar
being a const
method). Do they differ in any particular way, given the question's context? I would assume that both are okay here.
Disclaimer: I am aware of mutable
keyword, but this desing (not only being flawed) is simply an example. One could assume that the author of the code wanted to prohibit every single way of modifying vec
except for push_back
s.
Your quoted paragraph actually spelled out exactly what is undefined [dcl.type.cv]
Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.
A const reference/pointer to a non-const object doesn't make that object a const object, all your accesses are well-formed.