Вопрос

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

Это было полезно?

Решение

Если dynamic_cast должен выполнить, было бы неплохо использовать boost::polymorphic_downcast вместо этого, что выглядит примерно так:

assert(dynamic_cast<T*>(o) == static_cast<T*>(o));
return static_cast<T*>(o);

Таким образом, вы будете обнаруживать ошибки в отладочной сборке, в то же время избегая накладных расходов времени выполнения в сборке выпуска.

Если вы подозреваете, что приведение может завершиться неудачно, и вы хотите его обнаружить, используйте bad_cast и приведите к ссылочному типу. Это приведение будет вызывать if в случае ошибки и завершит работу вашей программы. (Это хорошо, если, как вы говорите, вы все равно не восстановитесь)

T& t = dynamic_cast<T&>(o);
t.func(); //< Use t here, no extra check required

Используйте assert для типа указателя, только если 0-указатель имеет смысл в контексте. Возможно, вы захотите использовать его в <=> таком виде:

if (T* t = dynamic_cast<T*>(o)) {
    t->func(); //< Use t here, it is valid
}
// consider having an else-clause

С помощью этой последней опции вам нужно убедиться, что путь выполнения имеет смысл, если <=> возвращает 0.

Чтобы ответить на ваш вопрос напрямую: я бы предпочел одну из двух первых альтернатив, которые я дал, чтобы в коде было явное <=>:)

Другие советы

bad_cast генерируется только при приведении ссылок

dynamic_cast< Derived & >(baseclass)

NULL возвращается при приведении указателей

dynamic_cast< Derived * >(&baseclass)

Так что никогда не нужно проверять оба.

Утверждение может быть приемлемым, но это в значительной степени зависит от контекста, и опять же, это верно практически для каждого утверждения ...

Да и нет.

boost::polymorphic_downcast<>, безусловно, является хорошим вариантом для обработки ошибок dynamic_cast<> на этапе отладки. Однако стоит отметить, что polymorphic_downcast<> следует использовать только тогда, когда можно предсказать полиморфный тип, переданный во время компиляции , в противном случае вместо него следует использовать <=>.

Однако последовательность:

if (T1* t1 = dynamic_cast<T1*>(o)) 
{ }
if (T2* t2 = dynamic_cast<T2*>(o)) 
{ }
if (T3* t3 = dynamic_cast<T3*>(o)) 
{ }

обозначает очень плохой дизайн, который должен быть решен с помощью полиморфизма и виртуальных функций .

Это зависит ...; -)

Если бы я действительно ожидал, что dynamic_cast даст мне что-то пригодное для использования, например, если я и никто другой не добавил полиморфный тип в контейнер указателей на базовый класс, то я бы пошел с приведением ссылки и позволил std::bad_cast убить мое приложение - больше ничего не поделаешь.

Однако, если я запрашиваю полиморфный тип для некоторой возможности, предоставляемой интерфейсом, который он не обязательно должен реализовывать, то я бы пошел с приведением указателя, и тогда NULL не был бы ошибкой ( если, конечно, я не ожидал, что возможность действительно будет присутствовать, - но тогда я пошел бы за эталонный состав в первую очередь ...)

Я бы согласился с ответом «все зависит», а также добавил бы «! пользователь теряет свою работу и т. д.). Я бы порекомендовал комбинацию утверждений и защитного программирования:

ptr = dynamic_cast<MyClass>(obj);
ASSERT(ptr);
if(ptr)
{
   // do stuff
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top