Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 96
Текст из файла (страница 96)
То есть информация теряется по сравнению с тем, что знает о состоянии программы отладчик. Поэтому для определенных людей, работающих с определенными программами в определенных средах разработки С+ч-, может оказаться предпочтительным не перехватывать исключения, на восстановление от которых программа пе рассчитана. 14.8. Исключения и эффективность В принципе, обработку исключений можно реализовать таким образом, что если исключение не сгенерировано, то во время выполнения не возникает никаких дополнителъных накладных расходов. Кроме того, обработку можно реализовать так, что генерация исключения окажется не намного дороже вызова функции.
Добиться этого без использования значительного количествадополнительной памяти, поддерживая при этом совместимость с последовательностью вызова, принятой в С, и соглашения, необходимые для отладчиков, н т. д., можно, но достаточно сложно. Однако не забывайте, что решения, альтернативные исключениям, тоже даются не даром.
Не так уж редко встречаются традиционные системы, половина кода которых занята обработкой ошибок. Глава 14, Обработка исключений 43Б Рассмотрим простую функциюЯ), которая вроде бы не имеет никакого отношения к обработке исключений; иоЫи(1пф иоиЩ ( еат'пд е; //- а(1); я(г); Но д() может сгенерировать исключение, поэтому Д) должна содержать код, гарантирующий, что в случае возникновения исключения е будет корректно уничтожена. С другой стороны, если бы и () не генерировала исключений, она должна была бы сообщить об ошибке каким-либо другим способом. Следовательно, аналогичный фрагмент, использующий обычный код обработки ошибок (а не исключения), сводится не к приведенной вьппе простой программе, а к чему-то вроде: Ьоо1д (1п ф Ьоо1/() ( е1г1пде; //.- (1 М(т)) 1/ (и (2)) ге1игп 1гие; е(ее гетигп/а1ее, е1ее ге1игп/и1ее; Все-таки обычно люди не обрабатывают ошибки столь систематически, да такая систематичность и не всегда важна.
Однако если существует необходимость в тщательной и систематической обработке ошибок, соответствующую работу лучше предоставить компьютеру, а именно механизму обработки исключений. Спецификации исключений Я 14.6) оказывают значительную помощь в улучшении качества генерируемого кода. Колы бы вы явно указали, что д () не может генерировать исключения: иоЫП(т1) тяго1и З; качество сгенерированного пляж() кода могло бы повыситься. Стоит иметь в виду, что ни одна функция традиционного С не генерирует исключений, поэтому в большинстве программ каждая функция С может быть обьявлена с пустой спецификацией 1пгош (). В частности, реализация знает, что только некоторые (негиногие) функции стандартной библиотеки С (такис как а1ех11() н дзог1 ()) могут генерировать исключения, и может воспользоваться этим фактом для генерации более качественного кода.
437 14.9. Альтернативные методы обработки ошибок До того как задать «функции С» пустую спецификацию исключений гйгов ]), задумайтесь на минутку, не может ли оца сгенерировать исключение. Например, она могла быть модифицирована с использованием оператора С++ леш, который может сгенерировать 6агг атос, или она может вызывать библиотечную функцию С++, которая генерирует исключения.
14.9. Альтернативные методы обработки ошибок Целью механизмов обработки исключений является предоставление средств для передачи из одной части программы в другую информации о том, что возникли «исключительные обстоятельства». Предполагается, что обе части программы написаны независимо, и что та часть программы, которая обрабатывает исключение, как правило может сделать что-нибудь осмысленное с возникшей ошибкой. Для эффективного использования обработчиков нам нужна общая стратегия. То есть различные части программы должны договориться о том, как используются исключения и где обрабатываются ошибки.
Механизмы обработки исключений нс локальны по своей сути, поэтому строгое следование общей стратегии является очень важным. Из этого следует, что стратегию обработки ошибок лучше всего планировать на самых ранних фазах проектирования. Из этого также следует, что стратегия должна быть простой (по сравнению со сложностью самой программы) п явной. Никто не будет последовательно придерживаться сложной стратегии в таких и без того трудных вопросах, как восстановление системы после возникновения ошибок. Прежде всего следует отвергнуть идею, что единственный механизм или метод может обработать все ошибки — это привело бы к черезмерной сложности.
Удачные, устойчивые к ошибкам системы являются многоуровневыми. Каждый уровень разбирается с таким количеством ошибок, которое он в состоянии «переварить», а прочие оставляет вьппестоящим уровням. С целью поддержки этой точки зрения вводится 1еглппа1е ]), предоставляющая выход в том случае, если сам механизм обработки исключенийий разруши.лся, или если он не полностью использован, н остались це перехваченные исключения. Аналогично, ипехрес1ег1 ]) предоставляет выход в тех случаях, когда защитная стратегия использования спецификаций исключений терпит неудачу. Пе все функции должны защищаться по «полной программе». В большинстве систем невозможно снабдить каждую функцию достаточным количеством проверок, чтобы гарантировать, что она завершится успешно или потерпит неудачу хорошо определенным образом. Причины, по которым это неосуществимо, различаются от программы к программе и от программиста к программисту.
Однако для больших программ: 11] Объем работы, необходимой для обеспечения таким образом понятой надежности слишком велик для того, чтобы быть выполненным полностью. [2] Накладные расходы времени и памяти неприемлемо велики (появляется склонность многократно проверять одни и те же ошибки, такие как недопустимые аргументы). ~3] Функции, написанные на других языках, не подчиняются установленным правилам игры. )4] Такое чисто локальное понятие «надежности» приводит к сложностям, которые становятся реальным бременем при обеспечении надежности системы в целом.
Глава ) 4. Обработка исключений 438 Тем не менее, разбиение программы на раздельные подсистемы, которые либо завершаются успешно, либо терпят неудачу строго определенным образом, представляется взжным, осуществимым и экономичным делом. Основные библиотеки, подсистемы и ключевые функции должны быть разработаны подобным образом. Спецификации исключений применяются как часть интерфейсов таких библиотек и подсистем. Как правило мы лишены роскоши проектирования всего кода системы с нуля. Соответственно, для реализации общей стратегии обработки ошибок во всех частях программы нам придется принять во внимание фрагменты, написанные с использованием стратегий, от.личных от нашей.
Чтобы сделать это, мы должны рассмотреть множество подходов, связанных со способами управления ресурсами в различных фрагментах программы и состоянием, в котором они оставляют систему после ошибки. Пель состоит в том, чтобы заставить фрагмент программы работать так, как если бы он следовал общей стратегии обработки ошибок, даже если внутри он придерживается другой схемы. Иногда возникает необходимость в смене лиля обработки ошибок. Например, после вызова библиотеки С мы можем проверить еггло и, возможно, сгенерировать исключение, илц, наоборот, перехватить исключения и установить еггло перед возвращением в С-программу нз библиотеки С~-~: оосд саИС () Ягоээ (С 61етн) ( еггло = 0; с 1илспоп(); Ц (еггпо) ( // очистка, если это возможно и необходимо 16гот С 61етй (еггло); ) ) ехсегл "С" оо1с(саИ/гот С () Ииот () ( ггу ( с р1ив Р1иэ /ипсцол (); ) сагс6 ', ) ( // алис~ока, если это возможно и необходилю еггпо = Е СРЕРЕРСТВЕЕ%УТ; В подобных случаях важно быть достаточно систематичным для обеспечения полного преобразования стиля обработки ошибок.
Обработка ошибок должна быть — насколько это возможно — иерархической. Если функция обнаруживает ошибку времени выполнения, она не должна обращаться за помощью к вызвавшей ее функции для восстановления или выделения ресурса. Такие запросы вводят циклы зависимостей в системе. Это в свою очередь делает программы сложнымц для понимания и порождает возможность бесконечных циклов в коде ооработкн ошибок н восстановления. Чтобы сделать код обработки ошибок более последовательным, следует применять упрощающие методы, такие как выделение ресурса есть инициализация», и упроща- 439 14.10. Стандартные исключения ющие предположения, такие как еисключенне представляет ошибку».