Использование блоков try / catch в C ++ - PullRequest
15 голосов
/ 04 июня 2009

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

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

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

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

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

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

AJ

Ответы [ 8 ]

17 голосов
/ 04 июня 2009

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

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

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

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

6 голосов
/ 04 июня 2009

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

5 голосов
/ 04 июня 2009

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

2 голосов
/ 04 июня 2009

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

1 голос
/ 04 июня 2009

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

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

0 голосов
/ 04 июня 2009

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

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

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

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

0 голосов
/ 04 июня 2009

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

0 голосов
/ 04 июня 2009

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

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

...