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?
Both orders of the cast should be fine and do the same thing.
const_castwill return a pointer pointing to the same object as before or a null pointer value if the argument is a null pointer value.dynamic_casteither returns a pointer pointing to aCheckBoxobject or a null pointer value, without depending on theconst, except that it refuses to cast away aconst.From looking at just the code you linked, it isn't clear to me though why the objects are stored as
constpointers in the first place.const_castis one of the more dangerous casts. You must guarantee that the pointer which youconst_castdoesn't actually point to an object withconsttype. If it does, then trying to modify the object through the new non-constpointer will cause undefined behavior.However in the code in your link there is an unrelated bug in the function. It uses
std::list::eraseto remove the elements while iterating over the list. It correctly uses the return value ofstd::list::eraseas a new iterator to the next element.But then, because the
forloop always executesit++, in the loop body youit--the return value fromstd::list::eraseto compensate.However, if you just removed the first element of the list, then
std::list::erasewill 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.