Когда и как я должен использовать обработку исключений? - PullRequest
72 голосов
/ 22 декабря 2010

Я читаю об обработке исключений. Я получил некоторую информацию о том, что такое обработка исключений, но у меня есть несколько вопросов:

  1. Когда выдается исключение?
  2. Вместо того, чтобы генерировать исключение, мы можем использовать возвращаемое значение, чтобы указать ошибку?
  3. Если я защищу все свои функции с помощью блоков try-catch, не снизит ли это производительность?
  4. Когда использовать обработку исключений?
  5. Я видел проект, в котором каждая функция в этом проекте содержала блок try-catch (т.е. код внутри всей функции окружен блоком try-catch). Это хорошая практика?
  6. В чем разница между try-catch и __try __except?

Ответы [ 7 ]

77 голосов
/ 22 декабря 2010

Вот довольно исчерпывающее руководство по исключениям, которые я считаю обязательными для прочтения:

Исключения и обработка ошибок - C ++ FAQ или C ++ FAQ lite

Как правило, выведите исключение, если ваша программа может определить external проблему, которая мешает выполнению. Если вы получаете данные с сервера и эти данные недействительны, выведите исключение. Недостаточно места на диске? Брось исключение. Космические лучи мешают вам обращаться к базе данных? Брось исключение. Но если вы получаете недопустимые данные из вашей собственной программы - не создавайте исключение. Если ваша проблема связана с вашим собственным плохим кодом, лучше использовать ASSERT для защиты от нее. Обработка исключений необходима для выявления проблем, которые программа не может обработать, и информирования их о пользователе, потому что пользователь может их обработать. Но ошибки в вашей программе не являются чем-то, что пользователь может обработать, поэтому сбой программы скажет не намного меньше, чем «Значение answer_to_life_and_universe_and_everything не равно 42! Это никогда не должно происходить !!!! 11» исключение.

Поймать исключение, в котором вы можете сделать что-то полезное, например, отобразить окно сообщения. Я предпочитаю ловить исключение один раз внутри функции, которая каким-то образом обрабатывает пользовательский ввод. Например, пользователь нажимает кнопку «Аннигилировать все гунны», а внутри функции annihiletAllHunamsClicked () есть блок try ... catch, чтобы сказать «я не могу». Несмотря на то, что уничтожение hunamkind - это сложная операция, требующая вызова десятков и десятков функций, существует только одна попытка ... поймать, потому что для пользователя это атомарная операция - одно нажатие кнопки. Проверка исключений в каждой функции избыточна и безобразна.

Кроме того, я не могу рекомендовать достаточно познакомиться с RAII - то есть, чтобы убедиться, что все инициализированные данные уничтожаются автоматически. И это может быть достигнуто путем максимально возможной инициализации в стеке, а когда вам нужно что-то инициализировать в куче, используйте какой-нибудь умный указатель. Все, что инициализировано в стеке, будет уничтожено автоматически при возникновении исключения. Если вы используете немые указатели в стиле C, вы рискуете утечку памяти при возникновении исключения, потому что нет никого, кто мог бы их очистить после исключения (конечно, вы можете использовать указатели в стиле C как члены вашего класса, но убедитесь, что они заботиться в деструкторе).

12 голосов
/ 22 декабря 2010

Исключения полезны в различных обстоятельствах.

Во-первых, есть некоторые функции, где стоимость вычисления предусловия настолько высока, что лучше просто выполнить расчет и прервать с исключением, еслиустановлено, что предварительное условие не выполнено.Например, вы не можете инвертировать единичную матрицу, однако, чтобы вычислить, является ли она единственной, вы вычисляете определитель, который очень дорог: это может быть сделано в любом случае внутри функции, поэтому просто «попробуйте» инвертировать матрицу и сообщитьошибка, если вы не можете сгенерировать исключение.По сути, это исключение как отрицательное предварительное условие использование.

Тогда есть другие случаи, когда ваш код уже сложен, и передача информации об ошибках по цепочке вызовов затруднена.Отчасти это связано с тем, что в C и C ++ есть сломанные модели структуры данных: есть и другие, более эффективные способы, но C ++ их не поддерживает (например, использование монад в Haskell).Это использование в основном Я не мог потрудиться сделать это правильно, поэтому я брошу исключение : это не правильный путь, но это практично.

Тогда есть основное использованиеисключения: сообщать, когда внешние предварительные условия или инварианты, такие как достаточные ресурсы, такие как память или дисковое пространство, недоступны.В этом случае вы обычно прекращаете работу программы или ее основного подраздела, и исключение является хорошим способом передачи информации о проблеме. C ++ Исключения были разработаны для сообщения об ошибках, которые препятствуют продолжению работы программы .

Модель обработки исключений, используемая в большинстве современных языков, включая C ++, известна как , чтобы ее нарушать.Это слишком сильно.Теоретики в настоящее время разработали лучшие модели, чем полностью открытая модель «бросай что-нибудь» и «возможно, а может и не поймать».Кроме того, использование информации о типе для классификации исключений было не очень хорошей идеей.

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

4 голосов
/ 25 января 2017

Если ваша проблема связана с вашим собственным плохим кодом, лучше использовать ASSERT для защиты от него.Обработка исключений необходима для выявления проблем, которые программа не может обработать, и информирования их о пользователе, потому что пользователь может их обработать.Но ошибки в вашей программе не являются чем-то, что пользователь может обработать, поэтому сбой программы скажет немногое

Я не согласен с этим аспектом принятого ответа .Утверждать не лучше, чем бросать исключение.Если исключения подходят только для ошибок во время выполнения (или «внешних проблем»), что означает std::logic_error для?

Логическая ошибка почти по определению является условием, препятствующим продолжению программы.Если программа представляет собой логическую конструкцию и условие возникает вне области этой логики, как она может продолжаться?Соберите свои данные, пока можете, и бросьте исключение!

Не похоже, что нет предшествующего уровня техники.std::vector, если не считать одного, выдает исключение логической ошибки, а именно std::out_of_range.Если вы используете стандартную библиотеку и не имеете обработчика верхнего уровня для перехвата стандартных исключений - если только для вызова what () и exit (3) - тогда вашпрограммы подлежат резкому молчанию, прекращению.

Макрос утверждения - намного более слабый защитник.Там нет восстановления.Если только вы не запускаете отладочную сборку, в этом случае не выполняется .Макрос утверждения относится к эпохе, когда вычисления были на 6 порядков медленнее, чем сегодня.Если вы столкнетесь с трудностями при проверке логических ошибок, но не будете использовать этот тест, когда он рассчитывает, в производственной среде, вам лучше быть уверенным в своем коде!

Стандартная библиотека предоставляетдля исключений логической ошибки, и использует их.Они существуют по причине: потому что логические ошибки происходят, и являются исключительными.Тот факт, что C поддерживает утверждения, не является основанием полагаться на такой примитивный (и, возможно, бесполезный) механизм, когда исключение намного лучше справляется с работой.

3 голосов
/ 20 августа 2013

Лучшее прочтение для этого

Об обработке исключений много говорили в последние полтора десятилетия.Однако, несмотря на общее согласие о том, как правильно обрабатывать исключения, разница в использовании продолжает существовать.Неправильную обработку исключений легко обнаружить, ее легко избежать, и она представляет собой простой показатель качества кода (и разработчика).Я знаю, что абсолютные правила выглядят как недальновидные или преувеличенные, но, как правило, вы не должны использовать try / catch

http://codebetter.com/karlseguin/2010/01/25/don-t-use-try-catch/

2 голосов
/ 22 декабря 2010

1. Проверка исключений включена в код, когда есть возможность получить исключение в результате или где-то между проблемами.

2. Используйте блок try-catch только в тех случаях, когдатребуется.Использование каждого блока try-catch добавляет дополнительную проверку условий, которая, безусловно, снижает оптимизацию кода.

3. Я думаю, что _try_except является допустимым именем переменной ....

0 голосов
/ 22 декабря 2010

Основное различие:

  1. один делает обработку ошибок для вас.
  2. один вы делаете самостоятельно.

    • Например, у вас есть выражение, которое может составить 0 divide error.Использование try catch 1. поможет вам при возникновении ошибки.Или вам нужно if a==0 then.. в 2.

    • Если вы не пытаетесь поймать исключение, я не думаю, что оно быстрее, просто его обход, если произошло error, это будет threw внешнему обработчику.

Вручение себя означает, что проблема не идет дальше, тогда во многих случаях преимущество в скорости, но не всегда.

Предложить: Просто разберись с собой, когда это просто и логично.

0 голосов
/ 22 декабря 2010

Многие пуристы C / C ++ вообще не одобряют исключения.Основные критические замечания:

  1. Это медленно - Конечно, это не очень "медленно".Тем не менее, по сравнению с чистым c / c ++, есть немало накладных расходов.
  2. Это приводит к ошибкам. Если вы неправильно обрабатываете исключения, вы можете пропустить код очистки в функции, которая выдаетисключение.

Вместо этого проверяйте возвращаемое значение / код ошибки при каждом вызове функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...