Я бы посоветовал не использовать ни один из них. Вместо этого catchисключения, которые вы не можете обработать, main()и просто returnоттуда. Это означает, что вам гарантировано, что раскрутка стека происходит правильно и вызываются все деструкторы. Другими словами:
int main(){try{// your stuff}catch(...){return1;// or whatever}}
@Neil: В основном согласен, но об исключениях, которые программа не может обработать, следует сообщать и повторно запускать. Пусть приложение вылетит.
Джон Диблинг,
13
Чтобы стек раскручивался, всегда нужно ловить main. Но я бы перебросил из улова. Поскольку некоторые ОС имеют возможность автоматически вызывать инфраструктуру отладки, если вы скомпилировали отладку.
Мартин Йорк,
5
Исключения, которые не обнаруживаются даже обработчиком верхнего уровня, могут вызвать средство системной отчетности, которое выгружает процесс и выгружает отчет об исключении для внимания разработчиков, например отчеты об ошибках Windows, отчеты об ошибках Mac OS X и журналы ошибок приложений iPhone.
JBRWilkinson
6
@John Причина, по которой меня удивляет, заключается в том, что, хотя это имеет смысл в свете того, как на самом деле реализуются исключения, он нарушает абстракцию, согласно которой исключение «распространяется вверх по стеку», пока не будет найден подходящий обработчик (или завершится не называется). А дырявые абстракции, часто неизбежные, неизбежно вызывают удивление, когда встречаются.
abort указывает на "ненормальный" конец программы и вызывает сигнал POSIX SIGABRT, что означает, что любой обработчик, который вы зарегистрировали для этого сигнала, будет вызван, хотя программа все равно завершит послесловие в любом случае. Обычно вы используете abortпрограмму на C для выхода из непредвиденного случая ошибки, когда ошибка скорее всего будет ошибкой в программе, а не чем-то вроде неправильного ввода или сбоя сети. Например, вы могли бы, abortесли было обнаружено, что в структуре данных есть указатель NULL, хотя по логике этого никогда не должно происходить.
exit указывает на "нормальный" конец программы, хотя это может указывать на сбой (но не на ошибку). Другими словами, вы можете exitполучить код ошибки, если пользователь ввел данные, которые не удалось проанализировать, или если файл не может быть прочитан. Код выхода 0 указывает на успех. exitтакже необязательно вызывает обработчики перед завершением программы. Они регистрируются с atexitи on_exitфункциями.
std :: terminate - это то, что автоматически вызывается в программе C ++ при возникновении необработанного исключения. По сути, это эквивалент C ++ abort, предполагающий, что вы сообщаете обо всех своих исключительных ошибках посредством выдачи исключений. Это вызывает обработчик, установленный std::set_terminateфункцией, которая по умолчанию просто вызывает abort.
В C ++ обычно нужно избегать вызова abortили exitошибки, поскольку лучше генерировать исключение и позволять коду дальше по стеку вызовов решать, подходит ли завершение программы. Независимо от того, используете ли вы exitдля успеха или нет, зависит от обстоятельств - имеет ли смысл завершить программу где-нибудь, кроме оператора return в main.
std::terminateследует рассматривать как последний инструмент сообщения об ошибках, даже в C ++. Проблема std::terminateзаключается в том, что обработчик завершения не имеет доступа к необработанному исключению, поэтому невозможно определить, что это было. Обычно гораздо лучше обернуть всю основную часть в try { } catch (std::exception& ex) { }блок. По крайней мере, тогда вы можете сообщить больше информации об исключениях, происходящих из std::exception(хотя, конечно, исключения, которые не являются производными, std::exceptionвсе равно останутся необработанными).
Обернуть тело mainin try { } catch(...) { }ненамного лучше, чем установить обработчик завершения, потому что снова у вас нет доступа к рассматриваемому исключению. Изменить: ответ Пер Нила Баттерворта, есть преимущество в том, что в этом случае стек разматывается, что (несколько удивительно) неверно для необработанного исключения.
Не имеет значения, что вы можете получить текущее исключение, поскольку вы не можете его проверить. Все, что вы можете сделать, это перебросить его.
Seattlecpp
2
@seattlecpp, вы можете перебросить его и поймать ссылку на него, которую затем можете проверить
gpeche
16
std :: abort и std :: exit (и другие: std :: _ Exit, std :: quick_exit) - это просто функции нижнего уровня. Вы используете их, чтобы сообщить программе, что именно вы хотите, чтобы она делала: какие деструкторы (и если) вызывать, какие еще функции очистки вызывать, какое значение возвращать и т. Д.
std :: terminate - это абстракция более высокого уровня: она вызывается (либо во время выполнения, либо вами), чтобы указать, что в программе произошла ошибка и что по какой-то причине ее невозможно обработать, выбрасывая исключение. Необходимость в этом обычно возникает, когда ошибка возникает в самом механизме исключения, но вы можете использовать ее в любое время, когда вы не хотите, чтобы ваша программа продолжалась после указанной ошибки. В своем посте я составил полный список ситуаций, когда вызывается std :: terminate. Не указано, что делает std :: terminate, потому что вы контролируете это. Вы можете настроить поведение, зарегистрировав любые функции. Ограничения, которые у вас есть, заключаются в том, что функция не может вернуться на сайт ошибки и не может выйти через исключение, но технически вы даже можете запустить свой насос сообщений внутри. Список полезных вещей, которые можно делать внутри, см. В другом моем посте .
В частности, обратите внимание, что std :: terminate считается обработчиком исключений в контекстах, где std :: terminate вызывается из-за сгенерированного исключения, которое не может быть обработано, и вы можете проверить, что это за исключение, и проверить его с помощью C ++ 11 с использованием std :: rethrow_exception и std :: current_exception. Все это в моем посте .
Желательно ли иметь обработчик очистки на случай, если программа завершится из-за системных сигналов? Например, недействительный доступ к памяти приводит к генерации сигнала SIGSEGV. В этом случае, хорошо ли просто позволить программе завершить работу и получить основной файл или зарегистрировать обработчик сигнала для выполнения очистки? Есть ли проблемы с очисткой при обработке системных сигналов по сравнению с очисткой при обработке std :: terminate?
Если ваша программа многопоточная, то вызов exit(), скорее всего, приведет к сбою, потому что глобальные / статические std::threadобъекты будут пытаться уничтожить без выхода из своих потоков.
Если вы хотите вернуть код ошибки и выйти из программы (более или менее) в обычном режиме, вызовите quick_exit()многопоточные программы. Для аварийного завершения (без возможности указать код ошибки) abort()или std::terminate()может быть вызван.
terminate () вызывается автоматически, когда возникает исключение, которое не может быть обработано. По умолчанию terminate () вызывает abort (). Вы можете установить собственный дескриптор с помощью функции set_terminate ().
abort () отправляет сигнал SIGABRT.
exit () - не обязательно плохо. Он успешно закрывает приложение и вызывает функции atexit () в порядке LIFO. Обычно я не вижу этого в приложениях C ++, однако я вижу это во многих приложениях на основе unix, где в конце он отправляет код выхода. Обычно выход (0) указывает на успешный запуск приложения.
std::abort
разумно, если исключение не может быть разрешено в деструкторе.std::terminate
этих статьях можно найти в превосходном блоге Анджея, посвященном C ++: akrzemi1.wordpress.com/2011/09/28/who-calls-stdterminate , akrzemi1.wordpress.com/2011/10/05/using-stdterminateОтветы:
Я бы посоветовал не использовать ни один из них. Вместо этого
catch
исключения, которые вы не можете обработать,main()
и простоreturn
оттуда. Это означает, что вам гарантировано, что раскрутка стека происходит правильно и вызываются все деструкторы. Другими словами:источник
abort указывает на "ненормальный" конец программы и вызывает сигнал POSIX SIGABRT, что означает, что любой обработчик, который вы зарегистрировали для этого сигнала, будет вызван, хотя программа все равно завершит послесловие в любом случае. Обычно вы используете
abort
программу на C для выхода из непредвиденного случая ошибки, когда ошибка скорее всего будет ошибкой в программе, а не чем-то вроде неправильного ввода или сбоя сети. Например, вы могли бы,abort
если было обнаружено, что в структуре данных есть указатель NULL, хотя по логике этого никогда не должно происходить.exit указывает на "нормальный" конец программы, хотя это может указывать на сбой (но не на ошибку). Другими словами, вы можете
exit
получить код ошибки, если пользователь ввел данные, которые не удалось проанализировать, или если файл не может быть прочитан. Код выхода 0 указывает на успех.exit
также необязательно вызывает обработчики перед завершением программы. Они регистрируются сatexit
иon_exit
функциями.std :: terminate - это то, что автоматически вызывается в программе C ++ при возникновении необработанного исключения. По сути, это эквивалент C ++
abort
, предполагающий, что вы сообщаете обо всех своих исключительных ошибках посредством выдачи исключений. Это вызывает обработчик, установленныйstd::set_terminate
функцией, которая по умолчанию просто вызываетabort
.В C ++ обычно нужно избегать вызова
abort
илиexit
ошибки, поскольку лучше генерировать исключение и позволять коду дальше по стеку вызовов решать, подходит ли завершение программы. Независимо от того, используете ли выexit
для успеха или нет, зависит от обстоятельств - имеет ли смысл завершить программу где-нибудь, кроме оператора return вmain
.std::terminate
следует рассматривать как последний инструмент сообщения об ошибках, даже в C ++. Проблемаstd::terminate
заключается в том, что обработчик завершения не имеет доступа к необработанному исключению, поэтому невозможно определить, что это было. Обычно гораздо лучше обернуть всю основную часть вtry { } catch (std::exception& ex) { }
блок. По крайней мере, тогда вы можете сообщить больше информации об исключениях, происходящих изstd::exception
(хотя, конечно, исключения, которые не являются производными,std::exception
все равно останутся необработанными).Обернуть тело
main
intry { } catch(...) { }
ненамного лучше, чем установить обработчик завершения, потому что снова у вас нет доступа к рассматриваемому исключению. Изменить: ответ Пер Нила Баттерворта, есть преимущество в том, что в этом случае стек разматывается, что (несколько удивительно) неверно для необработанного исключения.источник
std::current_exception()
. См. Пример здесь: akrzemi1.wordpress.com/2011/10/05/using-stdterminatestd :: abort и std :: exit (и другие: std :: _ Exit, std :: quick_exit) - это просто функции нижнего уровня. Вы используете их, чтобы сообщить программе, что именно вы хотите, чтобы она делала: какие деструкторы (и если) вызывать, какие еще функции очистки вызывать, какое значение возвращать и т. Д.
std :: terminate - это абстракция более высокого уровня: она вызывается (либо во время выполнения, либо вами), чтобы указать, что в программе произошла ошибка и что по какой-то причине ее невозможно обработать, выбрасывая исключение. Необходимость в этом обычно возникает, когда ошибка возникает в самом механизме исключения, но вы можете использовать ее в любое время, когда вы не хотите, чтобы ваша программа продолжалась после указанной ошибки. В своем посте я составил полный список ситуаций, когда вызывается std :: terminate. Не указано, что делает std :: terminate, потому что вы контролируете это. Вы можете настроить поведение, зарегистрировав любые функции. Ограничения, которые у вас есть, заключаются в том, что функция не может вернуться на сайт ошибки и не может выйти через исключение, но технически вы даже можете запустить свой насос сообщений внутри. Список полезных вещей, которые можно делать внутри, см. В другом моем посте .
В частности, обратите внимание, что std :: terminate считается обработчиком исключений в контекстах, где std :: terminate вызывается из-за сгенерированного исключения, которое не может быть обработано, и вы можете проверить, что это за исключение, и проверить его с помощью C ++ 11 с использованием std :: rethrow_exception и std :: current_exception. Все это в моем посте .
источник
quick_exit () !
Если ваша программа многопоточная, то вызов
exit()
, скорее всего, приведет к сбою, потому что глобальные / статическиеstd::thread
объекты будут пытаться уничтожить без выхода из своих потоков.Если вы хотите вернуть код ошибки и выйти из программы (более или менее) в обычном режиме, вызовите
quick_exit()
многопоточные программы. Для аварийного завершения (без возможности указать код ошибки)abort()
илиstd::terminate()
может быть вызван.Примечание: quick_exit () не поддерживается MSVC ++ до версии 2015.
источник
источник
terminate () вызывается автоматически, когда возникает исключение, которое не может быть обработано. По умолчанию terminate () вызывает abort (). Вы можете установить собственный дескриптор с помощью функции set_terminate ().
abort () отправляет сигнал SIGABRT.
exit () - не обязательно плохо. Он успешно закрывает приложение и вызывает функции atexit () в порядке LIFO. Обычно я не вижу этого в приложениях C ++, однако я вижу это во многих приложениях на основе unix, где в конце он отправляет код выхода. Обычно выход (0) указывает на успешный запуск приложения.
источник