Использование блоков try / catch в C ++

В общем, я обычно использую try / catch для кода, который имеет несколько точек сбоя, для которых сбой имеет общий обработчик.

По моему опыту, это обычно код, который квалифицирует ввод или контекст перед выполнением какого-либо действия или вывод после выполнения какого-либо действия.

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

Я хотел бы немного больше разобраться в основе приведенного выше совета:

  • Каков характер накладных расходов?
  • Существуют ли в последнее время рекомендации по разработке, которые касаются рекомендуемого использования (или предотвращения) блоков try / catch?
  • Насколько более быстрые процессоры и более современные компиляторы решают проблемы с try / catch?

Заранее спасибо за помощь,

AJ


person AJ S.    schedule 04.06.2009    source источник
comment
Я не уверен, что понимаю вопрос. Вас беспокоит производительность блоков try / catch? Или спрашивать об использовании try / catch для проверки ввода или что?   -  person jalf    schedule 04.06.2009
comment
Обман stackoverflow.com/questions/43253/ среди многих других   -  person    schedule 04.06.2009


Ответы (8)


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

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

Секунды - это "кодовый" подход. Каждый раз, когда код входит в блок try catch, концептуально местоположение блока помещается в стек. Это приводит к затратам при входе в блок try-catch и выходе из него, однако, когда возникает исключение, механизм времени выполнения может быстро выскочить из стека, чтобы найти, куда двигаться. Таким образом, создание исключений происходит (намного?) Быстрее, но за ввод блока теперь приходится платить. Помещение блока try catch в плотный цикл низкого уровня может привести к значительным накладным расходам.

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

person Todd Gardner    schedule 04.06.2009

Я нашел технический отчет о производительности C ++ (предупреждение в формате PDF ), в котором есть раздел об исключениях. Возможно, вам это будет интересно. У меня были коллеги, которые считали, что каждая инструкция в блоке try / catch связана с накладными расходами, но этот технический отчет, похоже, не поддерживает эту идею.

person Fred Larson    schedule 04.06.2009
comment
@ShawnChin: Так оно и было. Я нашел новую ссылку, а также понял, что неправильно присвоил бумагу. Я поправил сообщение. - person Fred Larson; 15.11.2012
comment
Более свежая версия этого отчета доступна здесь: open-std .org / jtc1 / sc22 / wg21 / docs / TR18015.pdf - person Shawn Chin; 15.11.2012

На ваш второй вопрос: общие рекомендации можно найти здесь, Херб Саттер также дает очень хороший совет здесь.

person Nikolai Fetissov    schedule 04.06.2009

Зависит от компилятора. Почему бы вам не написать простую функцию с блоком try-catch и аналогичную функцию без него и не сравнить сгенерированный машинный код?

person Nemanja Trifunovic    schedule 04.06.2009

Я нахожу сайт часто задаваемых вопросов по C ++, и в соответствующей книге есть поучительное обсуждение этого вопроса.

http://www.parashift.com/c++-faq-lite/exceptions.html

person Jherico    schedule 04.06.2009

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

На мой взгляд, у этого подхода есть две проблемы. 1) Пока я тестирую и отлаживаю, я не вижу ошибок и не имею возможности их исправить. 2) Это действительно ленивый выход. Вместо того чтобы обдумывать проблемы, которые могут возникнуть, и выяснять крайние случаи, я просто пытаюсь не потерпеть неудачу. Попытка не потерпеть неудачу во многом отличается от попытки добиться успеха.

person cmaxo    schedule 04.06.2009
comment
Всегда можно поймать и перебросить. Примечание. Если исключение ускользает из main (), оно определяется реализацией при размотке стека (поэтому деструкторы не могут быть вызваны). Таким образом, я всегда ловлю (...) и вхожу в основной и повторно бросаю, чтобы получить сообщение об ошибке Windows. - person Martin York; 04.06.2009

На большинстве языков вход в блок try / catch и выход из него с помощью обычных методов бесплатен, и только когда генерируется исключение, обработчик исключения ищет, где обработать исключение.

person Douglas Leeder    schedule 04.06.2009

В C ++ не следует использовать блоки try / catch для выполнения очистки. Вместо этого вы можете использовать шаблоны для получения ресурсов.

auto_ptr - один [плохой] пример

Блокировки синхронизации, при которых вы сохраняете мьютекс как переменную состояния и используете локальную переменную (шаблоны или обычные классы) для выполнения методов .acquire () /. Release ().

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

person Chris K    schedule 04.06.2009