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

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

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

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

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

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

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

AJ

Ответ 1

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

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

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

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

Ответ 2

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

Ответ 3

К вашему второму вопросу: общие рекомендации здесь, Herb Sutter также дает неплохой совет здесь.

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

Ответ 8

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

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

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

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