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).
Even though const_cast may remove constness or volatility from any pointer or reference, using the resulting pointer or reference to write to an object that was declared const or to access an object that was declared volatile invokes undefined behavior. So yes, modifying constant variables is undefined behavior.
Do not cast away a const qualification on an object of pointer type. Casting away the const qualification allows a program to modify the object referred to by the pointer, which may result in undefined behavior.
On the opposite end, the reason for const_cast to exist was adapting to old C code that did not support the const keyword. For some time functions like strlen would take a char* , even though it is known and documented that the function will not modify the object.
const_cast can be used to add const ness behavior too. From cplusplus.com: This type of casting manipulates the constness of an object, either to be set or to be removed.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With