I reviewed the kind of code below, and while I have a personal answer to the question (*), I'd like to have comments from C++/design experts.
For some reason, Data
is an object with a non-modifiable identifier, and a modifiable value:
class Data
{
const Id m_id ; // <== note that m_id is a const member variable
Value m_value ;
Data(const Id & id, const Value & value) ;
Data(const Data & data) ;
Data & operator = (const Data & data) ;
// etc.
} ;
The design choice became a language choice as the identifier was declared const
at class level (**), to avoid its (accidental) modification even from inside the class member functions...
... But as you can see, there is a copy-assignment operator, which is implemented as:
Data & Data::operator = (const Data & that)
{
if(this != &that)
{
const_cast<Id &>(this->m_id) = that.m_id ;
this->m_value = that->m_value ;
}
return *this ;
}
The fact the copy assignment operator is not const-qualified makes this code safe (the user can only legally call this method on a non-const object without provoking undefined behavior).
But is using const_cast
to modify an otherwise const member variable a good class design choice in C++?
I want to stress the following:
operator =
member function)const_cast
, too (move constructors/assignment and/or swap functions, for example), but not a lot.Note that this could have been a code review question, but this is not a "day-to-day" code. This is a general C++ type design question, with the need to balance the needs/power of a language and the code interpretation of patterns/idioms.
Note, too, that mutable
(as in C++98) is not a solution to the problem, as the aim is to make a member variable as unmodifiable as it can be. Of course, mutable
(as in C++11 post-"you don't know const
and mutable
" by Herb Sutter) is even less a solution.
(*) I can privately forward my answer to that question to anyone who asks.
(**) Another solution would have been to make the object non-const, and making it const at the interface level (i.e. not providing functions that can change it)
const_cast is one of the type casting operators. It is used to change the constant value of any object or we can say it is used to remove the constant nature of any object. const_cast can be used in programs that have any object with some constant value which need to be changed occasionally at some point.
const_cast is safe only if you're casting a variable that was originally non- const . For example, if you have a function that takes a parameter of a const char * , and you pass in a modifiable char * , it's safe to const_cast that parameter back to a char * and modify it.
Quote from cppreference:
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.
That means that your copy assignment is not safe, but plain incorrect. If you declare something const
, you cannot ever change it safely. This has nothing to do with design.
The only valid uses of const_cast
is removing constness from a const reference or pointer to a non-const object (or to a const object and then not modifying it, but then you can just not const_cast
instead).
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