Прервать, прекратить или выйти?

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

Ответ 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

quick_exit()!

Если ваша программа многопоточная, то вызов 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.