Какая разница между этими тремя, и как мне закончить программу в случае исключения, с которым я не могу нормально справиться?
Прервать, прекратить или выйти?
Ответ 1
Мой совет - не использовать никого из них. Вместо этого поймайте исключения, с которыми вы не можете справиться в main(), и просто возвращайтесь оттуда. Это означает, что вам гарантировано, что разворачивание стека происходит правильно и вызываются все деструкторы. Другими словами:
int main() {
try {
// your stuff
}
catch( ... ) {
return 1; // or whatever
}
}
Ответ 2
-
abort указывает на "ненормальный" конец программы и вызывает сигнал POSIX SIGABRT, что означает, что любой обработчик, который вы зарегистрировали для этого сигнала, будет вызван, хотя программа все равно прекратит использование слов в любом случае. Обычно вы используете
abort
в программе на C, чтобы выйти из непредвиденного случая ошибки, где ошибка, вероятно, будет ошибкой в программе, а не что-то вроде плохого ввода или сбоя сети. Например, вы могли быabort
, если бы была найдена структура данных с указателем NULL в ней, если это логически не произойдет. -
exit указывает на "нормальный" конец программы, хотя это может по-прежнему указывать на сбой (но не на ошибку). Другими словами, вы можете
exit
с кодом ошибки, если пользователь дал ввод, который не мог быть проанализирован, или файл не мог быть прочитан. Код выхода 0 указывает на успех.exit
также необязательно вызывает обработчики до того, как он закончит программу. Они регистрируются функциямиatexit
иon_exit
. -
std:: terminate - это то, что автоматически вызывается в программе на С++, когда есть необработанное исключение. Это по существу эквивалент С++ для
abort
, предполагая, что вы сообщаете обо всех своих исключительных ошибках с помощью исключения исключений. Это вызывает обработчик, который устанавливается функциейstd::set_terminate
, которая по умолчанию просто вызываетabort
.
В С++ вы обычно хотите избежать вызова abort
или exit
при ошибке, так как вам лучше сбросить исключение и позволить коду дальше вверх по стеку вызовов решить, подходит ли конец программы. Независимо от того, используете ли вы exit
для успеха, дело обстоятельство - имеет ли смысл закончить программу где-то иначе, чем оператор return в main
.
std::terminate
следует рассматривать как средство отчетности об ошибках последнего уровня, даже в С++. Проблема с std::terminate
заключается в том, что обработчик terminate не имеет доступа к исключению, которое прошло необработанным, поэтому нет способа сказать, что это было. Вы обычно гораздо лучше обертываете всю основную часть в блоке try { } catch (std::exception& ex) { }
. По крайней мере, вы можете сообщить больше информации об исключениях, полученных из std::exception
(хотя, конечно, исключения, которые не происходят из std::exception
, все равно будут обработаны без обработки).
Обтекание тела main
в try { } catch(...) { }
не намного лучше, чем установка обработчика завершения, потому что снова у вас нет доступа к рассматриваемому исключению. Изменить: Ответ на Нил Баттерворт: есть преимущество в том, что в этом случае стек разматывается, что (несколько удивительно) неверно для необработанного исключения.
Ответ 3
std:: abort и std:: exit (и больше: std:: _ Exit, std:: quick_exit) - это только функции нижнего уровня. Вы используете их, чтобы сообщить программе, что вы хотите, чтобы это точно: какие деструкторы (и если) вызывать, какие другие функции очистки вызывать, какое значение возвращать и т.д.
std:: terminate - это абстракция более высокого уровня: она вызывается (либо во время выполнения, либо для вас), чтобы указать, что произошла ошибка в программе, и по какой-то причине ее невозможно обработать, выбросив исключение. Необходимость в этом обычно возникает, когда ошибка возникает в самом механизме исключения, но вы можете использовать ее в любое время, когда вы не хотите, чтобы ваша программа продолжалась за пределами данной ошибки. Я собрал полный список ситуаций, когда std:: terminate называется в моем сообщении. Не указано, что делает std:: terminate, потому что вы контролируете его. Вы можете настроить поведение, зарегистрировав любые функции. Ограничения, которые у вас есть, это то, что функция не может вернуться на сайт ошибки и не может выйти из-за исключения, но технически вы даже можете запустить свой насос сообщений внутри. Список полезных вещей, которые вы можете сделать внутри, см. мой другой пост.
В частности, обратите внимание, что std:: terminate считается обработчиком исключений в контекстах, где std:: terminate вызывается из-за вызванного исключения, которое невозможно обработать, и вы можете проверить, что такое исключение, и проверить его, используя С++ 11 с использованием std:: rethrow_exception и std:: current_exception. Это все в моем сообщении.
Ответ 4
Если ваша программа многопоточная, то вызов exit()
, скорее всего, приведет к сбою, потому что объекты global/static std::thread
будут пытаться уничтожить, не выходя из своих потоков.
Если вы хотите вернуть код ошибки и выйти из программы (более или менее), вызовите quick_exit()
в многопоточных программах.
Для аномального завершения (без возможности указать код ошибки) можно вызвать abort()
или std::terminate()
.
Примечание: quick_exit() не поддерживается MSVС++ до версии 2015.
Ответ 5
-
terminate() автоматически вызывается когда возникает исключение, которое не может обрабатываться. По умолчанию terminate() вызывает abort(). Вы можете настроить дескриптор с функцией set_terminate().
abort() отправляет сигнал SIGABRT.
exit() не обязательно является плохим вещь. Он успешно завершает приложение и вызовы atexit() функции в порядке LIFO. Я не обычно см. это в С++ приложений, однако, я вижу это в многие приложения на основе UNIX, где отправляет код завершения в конце. Обычно выход (0) указывает на успешный запуск приложения.
Ответ 6
- terminate оставляет возможность зарегистрировать, что произойдет, когда оно будет вызвано. Должен быть один из двух других.
- exit - это обычный выход, позволяющий указать статус выхода. Выполняются обработчики, зарегистрированные с помощью at_exit().
- abort - ненормальный выход. Единственное, что выполняется, это обработчик сигнала для SIGABRT.