Портативно обрабатывать исключительные ошибки в C ++ - PullRequest
5 голосов
/ 02 сентября 2008

Я работаю над переносом приложения Visual C ++ на GCC (должно основываться на MingW и Linux).

Существующий код использует блоки __try { ... } __except(1) { ... } в нескольких местах, так что почти ничто (кроме, может быть, ошибок типа памяти?) Не может завершить работу программы без минимального ведения журнала.

Какие есть варианты сделать что-то подобное с GCC?

Редактировать: Спасибо за указатель на параметры / EH в Visual Studio. Теперь мне нужно несколько примеров того, как обрабатывать сигналы в Linux. Я нашел это сообщение с 2002 года.

Какие другие сигналы, кроме SIGFPE и SIGSEVG, мне следует остерегаться? (В основном заботятся о тех, кого можно поднять, если я делает что-то не так)

Информация о вознаграждении : Я хочу, чтобы мое приложение могло самостоятельно регистрировать столько ошибок, сколько возможно, до его выхода.

Какие сигналы я могу получить и какие из них, как правило, невозможно зарегистрировать после сообщения об ошибке? (Из памяти что еще?)

Как я могу обрабатывать исключения и (что наиболее важно) сигналы переносимым образом, чтобы код по крайней мере работал одинаково в Linux и MingW. #ifdef в порядке.

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

Ответы [ 5 ]

10 голосов
/ 02 сентября 2008

try {xxx} catch (...) {xxx} будет более переносимым, но может не так много ловить. Это зависит от настроек компилятора и окружения.

При использовании настроек VC ++ по умолчанию асинхронные (SEH) ошибки не доставляются в инфраструктуру C ++ EH; чтобы поймать их, вам нужно использовать обработчики SEH (кроме __try / __). VC ++ позволяет направлять ошибки SEH с помощью обработки ошибок C ++, что позволяет перехвату (...) перехватывать ошибки SEH; это включает ошибки памяти, такие как разыменование нулевого указателя. Подробнее .

Однако в Linux многие из ошибок, для которых Windows использует SEH, указываются с помощью сигналов. Они никогда не попадают в try / catch; для их обработки необходим обработчик сигнала.

0 голосов
/ 24 июля 2009

Перехват исключений C ++ с помощью catch(...) уже ставит вас в сумеречную зону.

Попытка отловить ошибки, которые не были обнаружены catch(...), помещает вас прямо в неопределенное поведение. Никакой код C ++ не гарантированно работает. Ваш минимальный код входа может привести к запуску ракеты.

Моя рекомендация - даже не пытаться catch(...). Поймайте только те исключения, которые вы можете осмысленно и безопасно зарегистрировать и позволить ОС обрабатывать все остальное, если таковые имеются

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

0 голосов
/ 23 июля 2009

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

Вот пример, который я сделал для другого вопроса, который относится и к вашему вопросу: ссылка

Также вы можете иметь более 1 улова:

try
{
   /* code that may throw exceptions */
}
catch (Error1 e1)
{
   /* code if Error1 is thrown */
}
catch (Error2 e2)
{
   /* code if Error2 is thrown */
}
catch (...)
{
   /* any exception that was not expected will be caught here */
}
0 голосов
/ 06 сентября 2008

Для переносимости, одна вещь, которую нужно попробовать - это использовать блоки try-catch для большинства исключений ванили, а затем установить обработчик завершения (set_terminate_handler), чтобы иметь минимальный доступный хук для катастрофических условий выхода. Вы также можете попробовать добавить что-то вроде обработчика atexit или on_exit. Конечно, ваша среда выполнения может быть странной или поврежденной, когда вы входите в эти функции, поэтому будьте осторожны с тем, насколько вы предполагаете нормальную среду.

Наконец, при использовании обычных пар try-catch вы можете рассмотреть возможность использования блоков try функции вместо открытия блока try в теле функции:

int foo(int x) try {
  // body of foo
} catch (...) {
   // be careful what's done here!
}

это относительно неизвестный кусок C ++ и может в некоторых случаях предлагать восстановление даже в случае частичного (мелкомасштабного) повреждения стека.

Наконец, да, вы, вероятно, захотите выяснить, какие сигналы вы можете обрабатывать самостоятельно, а какие можно прервать, и, если вы хотите использовать меньше механизмов обработки, вы могли бы рассмотреть возможность вызова не генерирующей версии оператор new и компиляция, чтобы при необходимости не генерировать исключения с плавающей запятой (вы всегда можете проверить isnan (.), isfinite (.) в результатах FP, чтобы защитить себя).

В этом последнем примечании, будьте осторожны: я заметил, что функции классификации результатов с плавающей запятой могут находиться в разных заголовках под linux и windows ... так что вам, возможно, придется обусловить эти включения.

Если вы чувствуете себя отважным, напишите все это, используя setjmp и longjmp (это шутка ...).

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

Почему бы не использовать стандартные исключения C ++ вместо проприетарного расширения MSFT? C ++ имеет концепцию обработки исключений.

struct my_exception_type : public logic_error {
    my_exception_type(char const* msg) : logic_error(msg) { }
};

try {
    throw my_exception_type("An error occurred");
} catch (my_exception_type& ex) {
    cerr << ex.what << endl;
}

В C ++ также есть предложение «catchall», поэтому, если вы хотите регистрировать исключения, вы можете использовать следующую оболочку:

try {
    // …
}
catch (...) {
}

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

...