Подтвердить что ты не робот

С++ dynamic_cast обработка ошибок

Есть ли хорошая практика, связанная с обработкой ошибок dynamic_cast (за исключением того, что вы не используете ее, когда вам не нужно)? Мне интересно, как мне идти NULL и bad_cast, которые он может бросить. Должен ли я проверить оба? И если я поймаю bad_cast или обнаруживаю NULL, я, вероятно, все равно не смогу восстановить... На данный момент я использую assert, чтобы проверить, не возвращает ли dynamic_cast не значение NULL. Приняли ли вы это решение при просмотре кода?

4b9b3361

Ответ 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
}