Как я могу перехватить все типы исключений в одном блоке перехвата? - PullRequest
10 голосов
/ 11 сентября 2008

В C ++ я пытаюсь перехватить все типы исключений за один раз (например, catch(Exception) в C #). Как это сделать? И более того, как можно ловить исключения деления на ноль?

Ответы [ 8 ]

23 голосов
/ 11 сентября 2008
catch (...)
{
   // Handle exceptions not covered.
}

Важные замечания:

  • Лучший подход заключается в том, чтобы отлавливать определенные типы исключений, которые вы можете фактически восстановить, в отличие от всех возможных исключений.
  • catch (...) также поймает некоторые серьезные системные ошибки (зависит от компилятора), от которых вы не сможете надежно восстановиться. Поймать их таким образом, а затем проглотить и продолжить, может вызвать дальнейшие серьезные проблемы в вашей программе.
  • В зависимости от вашего контекста может быть приемлемо использовать catch (...), при условии, что исключение будет переброшено. В этом случае вы регистрируете всю полезную информацию о локальном состоянии, а затем повторно генерируете исключение, чтобы оно распространялось вверх. Однако, если вы выберете этот маршрут, вам следует прочитать схему RAII .
14 голосов
/ 11 сентября 2008

Вы не хотите использовать catch (...) (то есть catch с многоточием), если вы действительно, безусловно, наиболее доказуемы, нуждаетесь в этом.

Причина этого в том, что некоторые компиляторы (Visual C ++ 6, чтобы назвать наиболее распространенными) также превращают ошибки, такие как ошибки сегментации и другие действительно плохие условия, в исключения, которые вы можете с радостью обработать с помощью catch (...). Это очень плохо, потому что вы больше не видите сбоев.

И технически, да, вы также можете поймать деление на ноль (для этого вам нужно будет использовать «StackOverflow»), но вам действительно следует избегать таких делений.

Вместо этого сделайте следующее:

  • Если вы действительно знаете, каких исключений ожидать, поймайте эти типы и не более, и
  • Если вам нужно выбросить исключения самостоятельно, и вам нужно перехватить все исключения, которые вы выбросите, сделайте эти исключения производными от std :: exception (как предложил Адам Пирс) и поймайте это.
5 голосов
/ 11 сентября 2008

Если вы находитесь в Windows и вам нужно обрабатывать ошибки, такие как деление на ноль и нарушение прав доступа, вы можете использовать структурированный транслятор исключений. И тогда внутри вашего переводчика вы можете выдать исключение c ++:

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)

4 голосов
/ 11 сентября 2008

Если перехват всех исключений - включая ОС - действительно то, что вам нужно, вам нужно взглянуть на свой компилятор и ОС. Например, в Windows вы, вероятно, используете ключевое слово «__try» или переключатель компилятора, чтобы заставить «try / catch» перехватывать исключения SEH или оба.

3 голосов
/ 11 сентября 2008

Сделайте все ваши собственные классы исключений наследуемыми от 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!";
    }
};
1 голос
/ 11 сентября 2008

Можно, конечно, использовать 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.

1 голос
/ 11 сентября 2008

В C ++ стандарт не определяет исключение деления на ноль, и реализации, как правило, не генерируют их.

0 голосов
/ 11 сентября 2008

Если я правильно помню (прошло уже много времени с тех пор, как я смотрел на C ++), я думаю, что следующее должно помочь

try
{
 // some code
}
catch(...)
{
 // catch anything
}

и быстрый Google (http://www.oreillynet.com/pub/a/network/2003/05/05/cpluspocketref.html), кажется, докажет, что я прав.

...