Как я могу перехватить все типы исключений в одном блоке catch?
-
09-06-2019 - |
Вопрос
В C++ я пытаюсь перехватить все типы исключений за один раз (например, catch(Exception)
в С#).Как это делается?И более того, как можно поймать исключения деления на ноль?
Решение
catch (...)
{
// Handle exceptions not covered.
}
Важные соображения:
- Лучший подход — перехватывать определенные типы исключений, от которых вы действительно можете восстановиться, а не все возможные исключения.
- catch(...) также перехватит некоторые серьезные исключения системного уровня (зависит от компилятора), от которых вы не сможете надежно восстановиться.Перехват их таким образом, а затем проглатывание и продолжение может вызвать дальнейшие серьезные проблемы в вашей программе.
- В зависимости от вашего контекста может быть приемлемо использовать catch(...), при условии, что исключение будет выброшено повторно.В этом случае вы регистрируете всю полезную информацию о локальном состоянии, а затем повторно генерируете исключение, чтобы оно могло распространиться.Однако вам следует прочитать Шаблон RAII если вы выберете этот маршрут.
Другие советы
Ты не хочу использовать catch (...) (т.е.поймать с помощью многоточия), если только у вас действительно, определенно и наиболее доказуемо, нет в этом необходимости.
Причина этого в том, что некоторые компиляторы (наиболее распространенные — Visual C++ 6) также превращают такие ошибки, как ошибки сегментации и другие действительно плохие условия, в исключения, которые вы с радостью можете обработать с помощью catch (...).Это очень плохо, потому что вы больше не увидите сбоев.
И технически, да, вы также можете уловить деление на ноль (для этого вам придется «StackOverflow»), но вам действительно следует избегать таких делений в первую очередь.
Вместо этого сделайте следующее:
- Если вы действительно знаете, какие исключения следует ожидать, перехватывайте именно эти типы и не более того, и
- Если вам нужно генерировать исключения самостоятельно и перехватывать все исключения, которые вы создадите, сделайте эти исключения производными от std::Exception (как предложил Адам Пирс) и перехватите их.
Если вы работаете в Windows и вам необходимо обрабатывать такие ошибки, как деление на ноль и нарушение прав доступа, вы можете использовать структурированный переводчик исключений.А затем внутри вашего переводчика вы можете создать исключение С++:
void myTranslator(unsigned code, EXCEPTION_POINTERS*)
{
throw std::exception(<appropriate string here>);
}
_set_se_translator(myTranslator);
Обратите внимание: код сообщит вам, в чем заключалась ошибка.Также вам необходимо скомпилировать с параметром /EHa (C/C++ -> Генератор кода -> Включить исключения C/C++ = Да с исключениями SEH).
Если это не имеет смысла, ознакомьтесь с документацией для [_set_se_translator](http://msdn.microsoft.com/en-us/library/5z4bw5h5(VS.80).aspx)
Если перехват всех исключений, включая исключения ОС, действительно то, что вам нужно, вам нужно взглянуть на свой компилятор и ОС.Например, в Windows у вас, вероятно, есть ключевое слово «__try» или переключатель компилятора, позволяющий «try/catch» перехватывать исключения SEH, или и то, и другое.
Сделайте так, чтобы все ваши пользовательские классы исключений наследовались от std::Exception, тогда вы сможете просто перехватить std::Exception.Вот пример кода:
class WidgetError
: public std::exception
{
public:
WidgetError()
{ }
virtual ~WidgetError() throw()
{ }
virtual const char *what() const throw()
{
return "You got you a widget error!";
}
};
В C++ стандарт не определяет исключение деления на ноль, и реализации, как правило, не выдают их.
Вы можете, конечно, использовать catch (...) { /* code here */ }
, но это действительно зависит от того, что вы хотите сделать.В C++ есть детерминированные деструкторы (никакой чепухи с финализацией), поэтому, если вы хотите все убрать, правильно будет использовать RAII.
Например.вместо:
void myfunc()
{
void* h = get_handle_that_must_be_released();
try { random_func(h); }
catch (...) { release_object(h); throw; }
release_object(h);
}
Сделайте что-то вроде:
#include<boost/shared_ptr.hpp>
void my_func()
{
boost::shared_ptr<void> h(get_handle_that_must_be_released(), release_object);
random_func(h.get());
}
Создайте свой собственный класс с деструктором, если вы не используете boost.
Если я правильно помню (прошло много времени с тех пор, как я смотрел на C++), я думаю, что следующее должно помочь
try
{
// some code
}
catch(...)
{
// catch anything
}
и быстрый гугл(http://www.oreillynet.com/pub/a/network/2003/05/05/cpluspocketref.html), кажется, доказывает мою правоту.