Универсализация обработки исключений
Есть у меня много методов, которые имеют такой вид
try {
.....
} catch (const MyException & e) {
return HandleError(e);
} catch (const std::exception & e) {
return HandleError(e);
}
И функции обработки
HRESULT HandleError(const std::exception & ex, HRESULT code) {
SetErrorInfo(ex.what());
return code;
}
HRESULT HandleError(const std::exception & ex) {
return HandleError(ex, E_UNEXPECTED);
}
HRESULT HandleError(const MyException & ex) {
return HandleError(ex, ex.code);
}
Вопрос: а нельзя ли сократить catch блок до такого вида
try {
.....
} catch (const std::exception & e) {
return HandleError(e);
}
А в самой функции уже принимать решение о том, что это за исключение и что с ним делать
HRESULT HandleError(const std::exception & ex) {
if (ex is MyException) // нужен оператор проверки класса-наследника
return HandleError(ex, dynamic_cast<MyException)(ex).code);
else
return HandleError(ex, E_UNEXPECTED);
}
Потому что нужно проверять несколько разных исключений из разных библиотек и у каждого есть свой код ошибки. Не хочется вставлять лесенку идентичных catch. Макросы пока не рассматриваю
Ответы (2 шт):
Конечно, dynamic_cast в помощь. Имея const std::exception &e, делаете вот так:
if (auto m = dynamic_cast<const MyException *>(&e)) {...}
Еще можно в HandleError ничего не передавать, и в ней делать try {throw;} и лесенку из catch-ей. Тогда в вызывающем коде можно просто писать catch (...) {return HandleError();}.
Если беспокоит возможность получить вылет, если вызвать такую функцию вне catch, то посмотрите в сторону std::current_exception - это замена throw;, но позволяет проверить, есть ли сейчас исключение.
Это делается посредством выбрасывания и повторного перехвата текущего исключения в другом контексте:
try
{
.....
}
catch (...)
{
return Handle_Error();
}
HRESULT Handle_Error(void) noexcept
{
try
{
throw;
}
catch (const MyException & e)
{
return e.code;
}
catch (const std::exception & e)
{
return E_UNEXPECTED;
}
catch (...)
{
return E_UNEXPECTED;
}
}