Программирование >>  Обобщенные обратные вызовы 

1 ... 19 20 21 [ 22 ] 23 24 25 ... 84


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

3. Когда следует использовать try и catch? Когда их не следует использовать? Изложите ваш ответ в виде рекомендации стандарта кодирования.

Вот один из вариантов ответа на этот вопрос.

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

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

Распространение ошибок. Помимо прочего, следует определить границы, которые не должно пересекать сгенерированное исключение. Обычно в роли таких границ выступает модуль или границы API.

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

2. Генерируйте исключение в месте обнаружения ошибки и не пытайтесь обработать его самостоятельно. (Понятно, что если код в состоянии сам справиться с возникшей ошибкой, то он не должен сообщать о ней!)

Документируйте каждую операцию - какие исключения может сгенерировать операция и почему. Такое описание должно быть частью документации каждой функции и каждого модуля. От вас не требуется писать спецификацию исключений для каждой функции (более того, как вы увидите в задаче 13, вы и не должны это делать), по вы должны ясно и точно документировать, чего следует ожидать вызывающей функции, поскольку семантика ошибок является частью интерфейса функции или модуля.

3. Используйте ключевые слова try и catch там, где у вас есть достаточно информации для обработки ошибки, ее преобразования или обеспечения границы, определенной стратегией обработки ошибок. В частности, я обнаружил, что для использования try и catch имеются три основные причины.

Для обработки ошибки. Это самый простой случай; произошла ошибка, мы знаем, что делать в такой ситуации, и мы выполняем эти действия. Жизнь продолжается (уже без исходного исключения, которое приказало долго жить). Если можно, то все необходимые действия лучше выполнять в деструкторе; если нет - использовать try/catch.

Для преобразования исключения. Это означает перехват одного исключения, которое сообщает о низкоуровневой ошибке, и генерацию другого исключения, в контексте своей собственной высокоуровневой семантики. Кроме того, исходное исключение может быть преобразовано в другое представление, например, код ошибки.

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



аутентификации. Функция Open может самостоятельно обработать все эти ситуации и не сообщать о них вызывающей функции, которой не известно, что такое пакет Foo или протокол ваг. Коммуникационный класс самостоятельно обрабатывает низкоуровневые ошибки, оставаясь в согласованном состоянии, и сообщает вызывающей функции только об ошибке высокого уровня, т.е. о том, что соединение не может быть установлено.

void session::open( /* ... */ ) { try {

все необходимые действия

catchC const ip error& err ) { - обработка lP-ошибки - освобождение ресурсов throw session::openFailed();

catchC const KerberosAuthentFai1& err ) { - обработка ошибки аутентификации - освобождение ресурсов throw Session::OpenFailed();

- - и т.д. ...

Для перехвата исключений на границе подсистемы. Эта ситуация, как правило, включает преобразование исключения, обычно в код ошибки или другое представление, не основанное на механизме исключений. Например, свертка стека доходит до функции, которая является частью интерфейса вашей подсистемы для языка С, у вас есть только два варианта действий - либо немедленно вернуть код ошибки из текущей функции API, либо установить состояние ошибки, которое вызывающая функция может опросить позже при помощи дополнительной функции API GetLastError.

> Рекомендация

Определите общую стратегию сообщений об ошибках и их обработки в

вашем приложении или подсистеме, и строго придерживайтесь се. Глобальная стратегия должна включать стратегии сообщений об ошибках, распространения ошибок и их обработки.

Используйте оператор throw там, где обнаружена ошибка, но нет возможности обработать ее самостоятельно.

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

Резюме

Один мудрый человек сказал: Либо веди сам, либо следуй за ведущим, либо уходи с дороги! Относительно безопасности исключений можно перефразировать это так: Либо генерируй исключение, либо обрабатывай его, либо уходи с дороги!

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



Задача 12. Безопасность исключений:

стоит ли овчинка выделки? Сложность: 7

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

Вопрос ДЛЯ профессионала

1. Вкратце опишите гарантии безопасности исключений Абрамса (базовую, строгую, отсутствия исключений).

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

а) базовой гарантии?

б) строгой гарантии?

в) гарантии отсугствия исключений?

Решение

Гарантии Абрамса

1. Вкратце опишите гарантии безопасности исключений Абрамса (базовую, строгую, отсутствия исключений).

Базовая гарантия (basic guarantee) заключается в том, что сбой при выполнении операции может изменить состояние программы, но не вызывает утечек и оставляет все объекты пригодными к дальнейшему использованию, в согласованном (но не обязательно предсказуемо.м) состоянии.

Строгая гарантия (strong guarantee) обеспечивает семантику транзакций: при сбое операции гарантируется неизменность состояния программы, относящегося к задействованным в операции объектам. Это означает отсутствие побочных эффектов операции, влияющих на состояние объектов, включая корректность или содержимое задействованных вспомогательных объектов, таких как итераторы, указывающие внутрь контейнеров, с которыми выполнялась операция.

И наконец, гарантия бессбойности (nofaiJ guarantee) означает невозможность возникновения сбоя, в контексте исключений это означает, что операция гарантированно их не генерирует. (Абраме и другие (в том числе в предыдущих книгах Exceptional С++) называли эту гарантию гарантией отсутствия исключений (nothrow guarantee). Я изменил это название на гарантию бессбойности, поскольку рассматриваемые гарантии относятся ко всем механизмам обработки ошибок, как с использованием исключений, так и без них.)

Какая именно гарантия нужна

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

а) базовой гарантии?

б) строгой гарантии?

в) гарантии отсутствия исключений?

Всегда следует писать код, отвечающий по крайней мере одной из перечисленных гарантий. Тому есть несколько причин.



1 ... 19 20 21 [ 22 ] 23 24 25 ... 84

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика