Есть ли хорошая практика, связанная с обработкой ошибок dynamic_cast (за исключением того, что вы не используете ее, когда вам не нужно)? Мне интересно, как мне идти NULL и bad_cast, которые он может бросить. Должен ли я проверить оба? И если я поймаю bad_cast или обнаруживаю NULL, я, вероятно, все равно не смогу восстановить... На данный момент я использую assert, чтобы проверить, не возвращает ли dynamic_cast не значение NULL. Приняли ли вы это решение при просмотре кода?
С++ dynamic_cast обработка ошибок
Ответ 1
Если dynamic_cast
должно быть успешным, было бы целесообразно использовать boost::polymorphic_downcast
вместо этого, что немного похоже на это:
assert(dynamic_cast<T*>(o) == static_cast<T*>(o));
return static_cast<T*>(o);
Таким образом, вы обнаружите ошибки в сборке отладки и в то же время избегаете служебных затрат времени выполнения в сборке выпуска.
Если вы подозреваете, что бросок может завершиться неудачно, и вы хотите его обнаружить, используйте dynamic_cast
и введите тип ссылки. Этот бросок будет бросать bad_cast
в случае ошибки и будет уничтожать вашу программу. (Это хорошо, если, как вы говорите, вы все равно не будете восстанавливаться)
T& t = dynamic_cast<T&>(o);
t.func(); //< Use t here, no extra check required
Используйте dynamic_cast
для типа указателя, только если 0-указатель имеет смысл в контексте. Вы можете использовать его в if
следующим образом:
if (T* t = dynamic_cast<T*>(o)) {
t->func(); //< Use t here, it is valid
}
// consider having an else-clause
С помощью этой последней опции вам необходимо убедиться, что путь выполнения имеет смысл, если dynamic_cast
возвращает 0.
Чтобы ответить на ваш вопрос напрямую: я бы предпочел одну из двух первых альтернатив, которые я дал, с явным assert
в коде:)
Ответ 2
bad_cast вызывается только при цитировании ссылок
dynamic_cast< Derived & >(baseclass)
NULL возвращается при указателях каста
dynamic_cast< Derived * >(&baseclass)
Поэтому никогда не нужно проверять оба.
Утверждение может быть приемлемым, но это сильно зависит от контекста, а затем снова это верно для почти всех утверждений...
Ответ 3
Да и нет.
boost::polymorphic_downcast<>
, безусловно, является хорошей возможностью обрабатывать ошибки dynamic_cast<>
во время фазы отладки. Однако стоит упомянуть, что polymorphic_downcast<>
следует использовать только тогда, когда возможно предсказать полиморфный тип, переданный во время компиляции, в противном случае вместо него следует использовать dynamic_cast<>
.
Однако последовательность:
if (T1* t1 = dynamic_cast<T1*>(o))
{ }
if (T2* t2 = dynamic_cast<T2*>(o))
{ }
if (T3* t3 = dynamic_cast<T3*>(o))
{ }
обозначает очень плохую конструкцию, которая должна определяться полиморфизмом и виртуальными функциями.
Ответ 4
Это зависит...; -)
Если бы я действительно ожидал, что dynamic_cast
даст мне что-то пригодное для использования, например, если я и никто другой не добавили полиморфный тип в контейнер указателей на базовый класс, тогда я бы пошел с ссылкой ссылки, и пусть std::bad_cast
убить мое приложение - на самом деле нечего делать.
Однако, если я запрашиваю полиморфный тип для некоторой возможности, открытой интерфейсом, который он не обязательно должен реализовывать, тогда я бы пошел с помощью указателя, а затем NULL не будет ошибкой ( если, конечно, я не ожидал, что на самом деле там действительно найдутся, - но потом я пошел на отправку ссылок в первую очередь...)
Ответ 5
Я согласен с ответом "это зависит", а также добавьте "Изящное деградация": просто потому, что листинг не получается, недостаточно, чтобы приложение не получилось (и пользователь потерял свою работу и т.д.)..). Я бы рекомендовал сочетание утверждений и защитного программирования:
ptr = dynamic_cast<MyClass>(obj);
ASSERT(ptr);
if(ptr)
{
// do stuff
}