Which is demonstrably evil. The developer has blown away the const across the whole object. Like all casts, this isn't a safe thing to do, and needs careful validation - but there are niche cases where it might be the only solution to a problem.
The mutable keyword prevents the effect of a const this pointer, but only for a particular field. Now the field can be changed legally within any const method. Which is, on the face of it, a Bad Thing.
But there are a few legitimate cases for doing this. A good example is where you want to hold a lock during a read of a constant object. std::mutex::lock is a non-const method, so the std::lock_guard uses a non-const reference. All of which means this won't work:
The solution is to make that mutex mutable - then the lock guard works and you're thread-safe.
But more importantly, while the method isn't "memory-const" anymore, it remains "semantically-const". To put it another way, unlike the previous examples I gave, this code behaves like you'd expect.
Oh, boiii. That looks pretty messy if you'd ask me. I just love how C++ can give you an infinite number of ways to shoot yourself in the foot. This is really funny, yet concerning. 😬
I wouldn't really count the mutable keyword since that's an actual feature of the language that allows you to "bypass" the const declaration.
However, I would definitely count the crazy type-casting. That, right there, is why you have to love and hate C++ at the same time.
Thanks for sharing this! This is genuinely one of the more interesting comments I've seen in this site for a while.
Impossible, eh? Strong words.
On a member function, the suffix const to a method declaration makes the implicit
this
argument itself const:That Foo::field() is really:
Since
this
is const, the field is also constant.So far, that's what you said. But C++ is well known for giving the programmer ample opportunity to shoot themselves in the foot.
One option is the const-cast:
Which is demonstrably evil. The developer has blown away the const across the whole object. Like all casts, this isn't a safe thing to do, and needs careful validation - but there are niche cases where it might be the only solution to a problem.
A more controlled mechanism is to use
mutable
:The
mutable
keyword prevents the effect of a constthis
pointer, but only for a particular field. Now the field can be changed legally within any const method. Which is, on the face of it, a Bad Thing.But there are a few legitimate cases for doing this. A good example is where you want to hold a lock during a read of a constant object. std::mutex::lock is a non-const method, so the
std::lock_guard
uses a non-const reference. All of which means this won't work:The solution is to make that mutex mutable - then the lock guard works and you're thread-safe.
But more importantly, while the method isn't "memory-const" anymore, it remains "semantically-const". To put it another way, unlike the previous examples I gave, this code behaves like you'd expect.
Oh, boiii. That looks pretty messy if you'd ask me. I just love how C++ can give you an infinite number of ways to shoot yourself in the foot. This is really funny, yet concerning. 😬
I wouldn't really count the
mutable
keyword since that's an actual feature of the language that allows you to "bypass" theconst
declaration.However, I would definitely count the crazy type-casting. That, right there, is why you have to love and hate C++ at the same time.
Thanks for sharing this! This is genuinely one of the more interesting comments I've seen in this site for a while.
Glad you found it interesting.
But the casts aren't inherently evil - they're a factor of C++ giving you all the tools you might need.