In a response to my comment to some answer in another question somebody suggests that something like
void C::f() const
{
const_cast<C *>( this )->m_x = 1;
}
invokes undefined behaviour since a const object is modified. Is this true? If it isn't, please quote the C++ standard (please mention which standard you quote from) which permits this.
For what it's worth, I've always used this approach to avoid making a member variable mutable
if just one or two methods need to write to it (since using mutable
makes it writeable to all methods).
It is undefined behavior to (attempt to) modify a const object (7.1.6.1/4 in C++11).
So the important question is, what is a const object, and is m_x
one? If it is, then you have UB. If it is not, then there's nothing here to indicate that it would be UB -- of course it might be UB for some other reason not indicated here (for example, a data race).
If the function f
is called on a const instance of the class C
, then m_x
is a const object, and hence behavior is undefined (7.1.6.1/5):
const C c;
c.f(); // UB
If the function f
is called on a non-const instance of the class C
, then m_x
is not a const object, and hence behavior is defined as far as we know:
C c;
const C *ptr = &c;
c->f(); // OK
So, if you write this function then you are at the mercy of your user not to create a const instance of C
and call the function on it. Perhaps instances of C
are created only by some factory, in which case you would be able to prevent that.
If you want a data member to be modifiable even if the complete object is const
, then you should mark it mutable
. That's what mutable
is for, and it gives you defined behavior even if f
is called on a const instance of C
.
As of C++11, const
member functions and operations on mutable
data members should be thread-safe. Otherwise you violate guarantees provided by standard library, when your type is used with standard library functions and containers.
So in C++11 you would need to either make m_x
an atomic type, or else synchronize the modification some other way, or as a last resort document that even though it is marked const, the function f
is not thread-safe. If you don't do any of those things, then again you create an opportunity for a user to write code that they reasonably believe ought to work but that actually has UB.