Who`s Afraid to Be Const Correct? Help Your Compiler Help You
(Page 1 of 4 )
In programs and commercial libraries that are not const-correct, you may find that const_cast is used. While a programmer may do this to force an application to do what he wants it to, it is never a good idea. Jun Nakamura explains why.
CONST_CASTUnfortunately there are commercial libraries available that are not const-correct. This is not an excuse for you to skimp on const-correctness, but it is one of the excuses to use const_cast.
A nasty cast it is, and it should catch your attention whenever you see it appear in code. The const_cast is a contract-breaker; it is a crowbar that you use when you want to make sure something is done your way.
My skin crawled when I noticed const_cast being used in a well-known middleware package:
void SomeClass::foo(AnotherClass const *ptr) {
m_data.pAnother = const_cast <AnotherClass *>(ptr);
}
Definitely the way const_cast is used in this function is a heavy breach of contract. I will even claim that the function is misleading and lying to you! When you study the interface of ‘SomeClass’ as declared in its header file, you expect to be able to safely pass a pointer to ‘AnotherClass’ that has the ‘foo()’ member function when you see that it is declared as:
void foo(AnotherClass const *ptr);
It clearly states that no changes will be made to the object you are passing in via a pointer.
But you have surrendered it unknowingly into the hands of ‘SomeClass’ that can do with it however it pleases, and you won’t know it until you take a look at the implementation of foo! This is clearly a case where the code is very const-incorrect, and pretends to be safe while it silently hijacks your object. The results of the const_cast are even undefined when the object passed in was originally declared as a const object!
I think that the creator of the library should either fix the code, or when the code base is simply too large and the consequences too far stretching… maybe just get rid of const altogether (or at least leave a big fat comment in the header file). I’d rather not get any directions when asking for them, instead of being sent the wrong way!
The First CONST_CAST ExcuseWhen you are using a commercial package that is not const-correct, you can use a const_cast so you can properly connect to its interface. Some libraries are known to implement strlen as: size_t strlen(char *s);
As long as you can correctly verify that your object won’t be modified, you can safely cast const away.
Make sure you only do this in the immediate layer connecting to code that is not const-correct, for it will affect your own code otherwise as well!
The Second CONST_CAST ExcuseThe second reason is quite an exotic one. When you remain conceptually const-correct (it is not observable from outside that data members are changed in the object… e.g. when caching the length of a label – see previous article) you will need the ‘mutable’ keyword. But how do you modify a const member data when your compiler doesn’t support the ‘mutable’ keyword?
You can cast const away from the ‘this’ pointer, which is either declared as ‘MyClass * const this;’ for non-const member functions or as ‘MyClass const * const this;’ for const member functions. Warning: you’re playing with fire now!
Here is a ‘mutable-free’ implementation of the ‘GetLabelLength’ function:
size_t MyClass::GetLabelLength() const {
if (-1 == m_LabelLength) {
MyClass* const self=const_cast<MyClass* const>(this);
self->m_LabelLength = strlen(m_pLabel);
}
return m_LabelLength;
}
Note that this is not always guaranteed to work. When the instanced MyClass object was declared const at its point of definition, the results of casting const away are undefined! (See also Item 21 “Use const whenever possible” [Meyers]).
At least you can recognize this hack now when you stumble upon it.
Next: The Compiler is Your Friend >>
More C++ Articles
More By J. Nakamura