Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is using const_cast regularly as a design tool acceptable?

Tags:

c++

const-cast

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:

  • Data is clearly a value type (it has an operator = member function)
  • in this pattern, a few other functions could legitimately need 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)

like image 964
paercebal Avatar asked Aug 10 '14 18:08

paercebal


People also ask

Why would you use const_cast?

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.

Is const_cast safe?

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.


1 Answers

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).

like image 173
Baum mit Augen Avatar answered Sep 28 '22 12:09

Baum mit Augen