Reputation: 21
I have a doubt about a line of the code written by my professor.
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
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