2010-05-12 2 views
78

В чем разница между этими тремя, и как мне закончить программу в случае исключения, которое я не могу обработать должным образом?прерывание, завершение или выход?

+3

Это не дубликат, а скорее подмножество с хорошими ответами http://stackoverflow.com/questions/397075/what-is-the-difference-between-exit-and-abort и помечено как C++ слишком! –

+0

'std :: abort' разумно, если исключение не может быть разрешено в деструкторе. – Daniel

+0

Для получения дополнительной информации о 'std :: terminate' см. Эти статьи в отличном блоге C++ в Andrzej: https://akrzemi1.wordpress.com/2011/09/28/who-calls-stdterminate, https: //akrzemi1.wordpress. com/2011/10/05/using-stdterminate/ –

ответ

6

Мой совет - не использовать ни один из них. Вместо этого поймайте исключения, с которыми вы не можете справиться в main(), и просто возвращайтесь оттуда. Это означает, что вам гарантировано, что разворачивание стека происходит правильно и вызываются все деструкторы. Другими словами:

int main() { 
    try { 
     // your stuff 
    } 
    catch(...) { 
     return 1; // or whatever 
    } 
} 
+0

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

+0

Зачем это удивлять? –

+4

@Neil: Согласовано в основном, но исключения, которые программа не может обрабатывать, должны сообщаться и обновляться. Пусть приложение рухнет. –

2
  • terminate оставляет за собой возможность зарегистрировать, что произойдет, когда оно будет вызвано. Должен быть один из двух других.
  • exit - это нормальный выход, позволяющий указать статус выхода. Обработчики, зарегистрированные с помощью at_exit(), запускаются
  • abort - ненормальный выход. Единственное, что выполняется, это обработчик сигнала для SIGABRT.
110
  • аборт указывает «аномальный» конец к программе, и поднимает сигнал SIGABRT POSIX, а это значит, что любой обработчик, который вы зарегистрировали для этого сигнала будет вызван, хотя в любом случае программа будет по-прежнему прервать последующие слова. Обычно вы должны использовать abort в программе на C, чтобы выйти из непредвиденного случая ошибки, где ошибка, скорее всего, будет ошибкой в ​​программе, а не что-то вроде плохого ввода или сбоя сети. Например, вы могли бы abort, если бы была найдена структура данных с указателем NULL, когда это должно логически никогда не происходить.

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

  • std :: terminate - это то, что автоматически вызывается в программе на C++, когда есть необработанное исключение. Это по существу эквивалент C++, равный abort, предполагая, что вы сообщаете обо всех своих исключительных ошибках с помощью исключения исключений. Это вызывает обработчик, который устанавливается функцией std::set_terminate, которая по умолчанию просто вызывает abort.

В C++, обычно требуется, чтобы избежать вызова abort или exit об ошибке, так как вы лучше бросать исключение и дать код дальше стека вызовов решить или нет завершения программы является целесообразным. Независимо от того, используете ли вы exit для успеха, это вопрос обстоятельств - имеет ли смысл закончить программу где-то, кроме оператора возврата, в main.

std::terminate следует рассматривать как средство отчетности об ошибках последнего времени, даже на C++. Проблема с std::terminate заключается в том, что обработчик завершения имеет , а не, имеет доступ к исключению, которое прошло необработанным, поэтому нет способа сказать, что это было. Вы обычно намного лучше обертываете всю основную часть в блоке try { } catch (std::exception& ex) { }.По крайней мере, вы можете сообщить дополнительную информацию об исключениях, которые получены из std::exception (хотя, конечно, исключения, которые не происходят из std::exception, все равно будут необработаны).

Обтекание тела main в try { } catch(...) { } не намного лучше, чем установка обработчика завершения, потому что снова у вас нет доступа к рассматриваемому исключению. Редактировать: Ответ Пер Нила Баттерворта, есть преимущество в том, что в этом случае стека раскручивается, что (несколько удивительно) неверно для необработанного исключения.

+9

Можете ли вы обновить этот ответ с помощью C++ 11 info? Кажется, что теперь есть способы получить исключение в catch (...) и в обработчике terminate. – Klaim

+0

В C++ обработчик terminate * имеет * доступ к исключению через 'std :: current_exception()'. См. Пример здесь: https://akrzemi1.wordpress.com/2011/10/05/using-stdterminate/ – anorm

+0

Не имеет значения, что вы можете получить текущее исключение, так как вы не можете его проверить. Все, что вы можете сделать, это перебросить его. – seattlecpp

4
  • прекращается() автоматически вызывается , когда происходит исключение, которое не может быть обработано . По умолчанию terminate() вызывает abort(). Вы можете установить настраиваемый дескриптор с функцией set_terminate().

    abort() посылает сигнал SIGABRT.

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

+7

Неудачный! Как в Unix, так и в DOS, exit (0) указывает на успех и любое другое значение, переданное exit() указывает на сбой, а не наоборот. –

+0

-1 неудачно, не удалось – Petter

13

станд :: прервать и станд :: выход (и больше: станд :: _ Выход, станд :: quick_exit) только нижние функции уровня. Вы используете их, чтобы сообщить программе, что вы хотите, чтобы точно: какие деструкторы (и если) вызывать, какие другие функции очистки для вызова, какое значение нужно вернуть и т. Д.

std :: terminate is a абстракция более высокого уровня: она называется (либо временем выполнения, либо вами), чтобы указать, что произошла ошибка в программе, и по какой-то причине ее невозможно обработать, выбросив исключение. Необходимость в этом обычно возникает, когда ошибка возникает в самом механизме исключения, но вы можете использовать ее в любое время, когда вы не хотите, чтобы ваша программа продолжалась за пределами данной ошибки. Я собрал полный список ситуаций, когда std :: terminate называется in my post. Не указано, что делает std :: terminate, потому что вы контролируете его. Вы можете настроить поведение, зарегистрировав любые функции. Ограничения, которые у вас есть, это то, что функция не может вернуться на сайт ошибки и не может выйти из-за исключения, но технически вы даже можете запустить свой насос сообщений внутри. Список полезных вещей, которые вы можете сделать внутри, см. В разделе my other post.

В частности, обратите внимание, что std :: terminate считается обработчиком исключений в контекстах, где std :: terminate вызывается из-за вызванного исключения, которое невозможно обработать, и вы можете проверить, что такое исключение, и проверить его на используя C++ 11, используя std :: rethrow_exception и std :: current_exception. Это все в my post.

6

quick_exit()!

Если программа многопоточная, то вызов exit(), скорее всего, приведет к аварии, поскольку глобальные/статические объекты std::thread будет предпринята попытка уничтожить, не выходя их нитками.

Если вы хотите вернуть код ошибки и выйти из программы (более или менее), вызовите quick_exit() в многопоточных программах. Для аномального завершения (без возможности указать код ошибки) можно назвать abort() или std::terminate().

Примечание: quick_exit() has not been supported by MSVC++ до версии 2015 года.

+0

спасибо! это действительно помогло мне! – sailfish009

Смежные вопросы