Однажды мне посоветовали, что программа на C ++ должна в конечном итоге перехватывать все исключения. В то время аргументация сводилась к тому, что программы, допускающие появление исключений за пределами, main()
переходят в странное состояние зомби. Мне сказали об этом несколько лет назад, и в ретроспективе я считаю, что наблюдаемое явление было связано с длительным созданием исключительно больших дампов ядра из рассматриваемого проекта.
В то время это казалось странным, но убедительным. Было совершенно бессмысленно, что C ++ должен «наказать» программистов за то, что они не перехватили все исключения, но доказательства, которые были до меня, похоже, подтверждали это. Для рассматриваемого проекта программы, которые выдавали неисследованные исключения, действительно входили в странное состояние зомби - или, как я подозреваю, причина была в том, что процесс посреди нежелательного дампа ядра необычайно трудно остановить.
(Для тех, кто интересуется, почему это не было более очевидным в то время: проект генерировал большое количество выходных данных в нескольких файлах из нескольких процессов, которые эффективно скрывали любые aborted (core dumped)
сообщения, и в этом конкретном случае посмертная проверка дампов ядра не была не является важной техникой отладки, поэтому дампы ядра не были особо продуманы. Проблемы с программой обычно не зависели от состояния, накопленного во многих событиях с течением времени долгоживущей программой, а скорее исходных входных данных для недолговечной программы (< 1 час), поэтому было практичнее просто перезапустить программу с теми же входными данными из отладочной сборки или в отладчике, чтобы получить больше информации.)
В настоящее время я не уверен в том, есть ли какое-либо существенное преимущество или недостаток в вылове исключений исключительно с целью предотвращения выхода исключений main()
.
Небольшое преимущество, которое я могу придумать, позволяя исключениям возникать в прошлом, main()
заключается в том, что это приводит к тому, что результат std::exception::what()
выводится на терминал (по крайней мере, для программ, скомпилированных gcc в Linux). С другой стороны, это тривиально, если вместо этого перехватить все исключения, полученные из, std::exception
и распечатать результат, std::exception::what()
и если желательно напечатать сообщение из исключения, которое не является производным, std::exception
оно должно быть перехвачено перед отправкой main()
, чтобы напечатать сообщение.
Скромный недостаток, который я могу придумать для того, чтобы разрешить возникновение исключений, main()
заключается в том, что могут генерироваться нежелательные дампы ядра. Для процесса, использующего большой объем памяти, это может быть довольно неприятно, и для управления поведением дампов ядра из программы требуются вызовы функций для конкретной ОС. С другой стороны, если желательны дамп ядра и выход, тогда вместо этого это может быть достигнуто в любое время с помощью вызова, std::abort()
а выход без дампа ядра может быть достигнут в любое время с помощью вызова std::exit()
.
Кстати, я не думаю, что когда-либо видел what(): ...
сообщение по умолчанию, распечатанное широко распространенной программой после сбоя.
Что, если таковые имеются, являются сильными аргументами за или против того, чтобы исключения C ++ всплыли в прошлом main()
?
Изменить: на этом сайте есть много общих вопросов обработки исключений. Мой вопрос касается, в частности, исключений C ++, которые не могут быть обработаны и дошли до них main()
- возможно, может быть напечатано сообщение об ошибке, но это ошибка немедленного показа остановки.
источник
Ответы:
Одной из проблем, связанных с пропуском исключений после main, является то, что программа завершится вызовом, к
std::terminate
которому следует обращаться по умолчаниюstd::abort
. Реализация определяется только в том случае, если раскрутка стека выполняется перед вызовом,terminate
поэтому ваша программа может завершиться без вызова одного деструктора! Если у вас есть какой-то ресурс, который действительно необходимо восстановить с помощью вызова деструктора, вы в затруднительном положении ...источник
std::abort
, нет и, следовательно, ошибочные утверждения тоже не делают. Также стоит отметить, что в современных ОС сама ОС будет очищать много ресурсов (память, дескрипторы файлов, ...), которые связаны с идентификатором процесса. Наконец, я также намекал на «Защиту в глубине»: ненадежно ожидать, что все другие процессы защищены от ошибок и всегда будут высвобождать полученные ими ресурсы (сеансы, красиво заканчивать написание файлов, ...), которые вы должны запланировать это ...WM_POWERBROADCAST
сообщение. Это работает только в том случае, если ваш компьютер работает от батареи (если вы используете ноутбук или ИБП).Основная причина, по которой вы не позволяете избежать исключений,
main
заключается в том, что в противном случае вы теряете возможность контролировать то, как о проблеме сообщают ваши пользователи.Для программы, которая не предназначена для использования в течение длительного времени или широко распространена, может быть приемлемым, чтобы о непредвиденных ошибках сообщалось любым способом, которым ОС решает это сделать (например, показывая диалоговое окно с сообщением об ошибке в вашем лице в Windows ).
Для программ, которые вы продаете или которые предоставлены широкой публике организацией, имеющей репутацию, которую следует поддерживать, обычно лучше сообщить о том, что вы столкнулись с неожиданной проблемой, и попытаться сохранить как можно большую часть данные пользователя по возможности. Не потерять полдня работы своего пользователя и не потерпеть неожиданный сбой, но отключить его изящно, как правило, намного лучше для вашей деловой репутации, чем альтернатива.
источник
main()
имеет много общего с ОС? ОС может ничего не знать о C ++. Я предположил, что это определяется кодом, который компилятор вставляет где-то в программу.TL; DR : Что говорит спецификация?
Технический обход ...
Когда выдается исключение и никакой обработчик не готов к нему:
std::terminate
называется, который по умолчанию прерываетсяПоследний может быть полезен для очень редких ошибок (потому что их воспроизведение - трата времени).
Уловить ли все исключения или нет, в конечном счете, вопрос спецификации:
Для любой производственной программы это должно быть указано, и вы должны следовать спецификации (и, возможно, утверждать, что она будет изменена).
Для быстро собранных программ, которые будут использоваться только техническими специалистами (вы, ваши товарищи по команде), подойдет любая. Я рекомендую разрешить сбой и настроить среду, чтобы получить отчет или нет в зависимости от ваших потребностей.
источник
Исключение, которое вы ловите, дает вам возможность напечатать приятное сообщение об ошибке или даже попытаться исправить ошибку (возможно, просто перезапустив приложение).
Однако в C ++ исключение не содержит информацию о состоянии программы, когда она была выброшена. Если вы поймете это, все такое состояние будет забыто, тогда как если вы позволите программе аварийно завершить работу, состояние обычно все еще там и может быть прочитано из дампа программы, что облегчает отладку.
Так что это компромисс.
источник
В тот момент, когда вы знаете, что вам нужно прервать, продолжайте и звоните
std::terminate
уже, чтобы сократить дальнейший ущерб.Если вы знаете, что можете безопасно свернуть, сделайте это вместо этого. Помните, что разматывание стека не гарантируется, когда исключение никогда не перехватывается, поэтому перехватывайте и перебрасывайте.
Если вы можете безопасно сообщить / зарегистрировать ошибку лучше, чем система сделает это самостоятельно, продолжайте.
Но будьте уверены, что случайно не усугубите ситуацию.
Часто бывает слишком поздно сохранять данные при обнаружении неисправимой ошибки, хотя это зависит от конкретной ошибки.
В любом случае, если ваша программа написана для быстрого восстановления, просто убить ее - лучший способ завершить ее, даже если это обычное завершение работы.
источник
Большую часть времени грациозно разбивать - это хорошо, но есть и компромиссы. Иногда это хорошая вещь, чтобы потерпеть крах. Я должен отметить, что я в основном думаю об отладке в очень большом. Для простой программы - хотя это все еще может быть полезно, она нигде не так полезна, как с очень сложной программой (или несколькими сложными программами, взаимодействующими).
Вы не хотите аварийно завершать работу публично (хотя это действительно неизбежно - аварийное завершение программ, и действительно математически проверяемая не сбойная программа - это не то, о чем мы здесь говорим). Подумайте о BSOD Билла Гейтса во время демонстрации - плохо, правда? Тем не менее, мы можем попытаться выяснить, почему мы потерпели крах, и не потерпели крах таким же образом.
Я включил функцию отчетов об ошибках Windows, которая создает локальные аварийные дампы для необработанных исключений. Это чудесно, если у вас есть файлы символов, связанные с вашей (сбойной) сборкой. Интересно, потому что я создал этот инструмент, я хочу , чтобы разбить более - потому что я узнал из каждой аварии. Тогда я могу исправлять ошибки и меньше вылетать.
Итак, на данный момент я хочу, чтобы мои программы перебрасывались до самого верха и вылетали. В будущем я мог бы хотеть изящно съесть все мои исключения - но не, если я смогу заставить их работать на меня.
Вы можете прочитать больше о локальных дампах сбоя здесь, если вам интересно: Сбор дампов пользовательского режима
источник
В конечном счете, если исключение всплывет после main (), оно может привести к сбою вашего приложения, и, на мой взгляд, приложение никогда не должно аварийно завершить работу. Если это нормально, чтобы вывести приложение из строя в одном месте, то почему нигде? Зачем вообще заниматься обработкой исключений? (Сарказм, на самом деле не предлагая этого ...)
У вас может быть глобальная попытка / отлов, которая печатает элегантное сообщение, сообщающее пользователю, что произошла неустранимая ошибка, и что им нужно отправить электронное письмо Бобу об этом или о чем-то подобном, но падение совершенно непрофессионально и недопустимо. Это легко предотвратить, и вы можете информировать пользователя о том, что только что произошло, и о том, как исправить ситуацию, чтобы она больше не повторилась.
Сбой - это чисто любительский час.
источник
main
. Если вы не знаете, как с этим справиться, притворяться, что вы это делаете, очевидно, действительно ужасная ошибка.