bandomatteo
bandomatteo

Reputation: 21

C++ const_cast over a dynamic_cast and vice versa

I have a doubt about a line of the code written by my professor.

This is the full code.

The relevant function is:

std::vector<AbstractButton*> removeUnchecked() {
    std::vector<AbstractButton*> v;
    CheckBox* p;
    for(auto it = Buttons.begin(); it != Buttons.end(); ++it) {
      p = const_cast<CheckBox*>(dynamic_cast<const CheckBox*>(*it));
      if(p && !(p->isChecked())) {
    v.push_back(p);
    it = Buttons.erase(it); --it;
      }
    }
    return v;
  }

The class Gui has a std::list<const AbstractButton*> Buttons and the function std::vector<AbstractButton*> removeUnchecked(){} wants a vector as its return type. We had to remove from the Gui every checkable buttons with the attribute checked == false and put it into the returned vector.

The professor wrote:

CheckBox* p = const_cast<CheckBox*>(dynamic_cast<const CheckBox*>(*it));

performing a dynamic_cast first, and then a const_cast.

If I had written:

CheckBox* p  = dynamic_cast<CheckBox*>(const_cast<AbstractButton*>(*it))

const_cast first, and then dynamic_cast, would it be the same thing?

Upvotes: 2

Views: 532

Answers (1)

user17732522
user17732522

Reputation: 76688

Both orders of the cast should be fine and do the same thing.

const_cast will return a pointer pointing to the same object as before or a null pointer value if the argument is a null pointer value.

dynamic_cast either returns a pointer pointing to a CheckBox object or a null pointer value, without depending on the const, except that it refuses to cast away a const.


From looking at just the code you linked, it isn't clear to me though why the objects are stored as const pointers in the first place.

const_cast is one of the more dangerous casts. You must guarantee that the pointer which you const_cast doesn't actually point to an object with const type. If it does, then trying to modify the object through the new non-const pointer will cause undefined behavior.


However in the code in your link there is an unrelated bug in the function. It uses std::list::erase to remove the elements while iterating over the list. It correctly uses the return value of std::list::erase as a new iterator to the next element.

But then, because the for loop always executes it++, in the loop body you it-- the return value from std::list::erase to compensate.

However, if you just removed the first element of the list, then std::list::erase will return a pointer to the new first element of the list, i.e. the new .begin() iterator. Decrementing this pointer is not allowed and causes undefined behavior.

Upvotes: 1

Related Questions