Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [ 23 ] 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

аутентификации. Функция 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. Исключения всегда возможны. Их может сгенерировать стандартная библиотека. Они могут порождаться языком программирования. Наш код должен быть к этому готов. К счастью, это небольшая беда, поскольку теперь мы знаем, что с ними делать. Нам надо просто принять некоторые правила поведения и строго им следовать.

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

2. Написание безопасного с точки зрения исключений кода - правило хорошего тона. Безопасность кода и его качество взаимосвязаны. Распространенные методы написания безопасного в плане исключений кода вполне применимы и в случае отсутствия исключений. Рассмотрим основные приемы, облегчающие написание безопасного кода.

• Использование идиомы "распределение ресурса есть инициализация" для работы с ресурсами. Использование таких объектов-владельцев ресурсов, как классы Lock и shared ptr (см. [Boost, Suttert)2a]), - хорошая мысль безотносительно к безопасности исключений. Не удивительно, что к достоинствам таких классов относится и безопасность исключений. Сколько раз вам приходилось встречаться с функциями (понятно, что мы не говорим о ваших собственных функциях, разговор идет о чужом коде), в которых в ветви, приводящей к преждевременному возврату из функции, не выполнялось необходимое освобождение ресурсов? А ведь достаточно было использовать указанную идиому, и все эти действия были бы выполнены автоматически.

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

• Следование принципу "один класс (одна функция) - одно действие". Функции, выполняющие несколько действий, например stack: :Рор или EvaluateSalaryAn-dReturnName из книги [SutterOO], очень сложно сделать строго безопасными в смысле исключений. Многие проблемы, связанные с безопасностью исключений, можно решить, просто придерживаясь указанного принципа. Это правило появилось задолго до того, как стало понятно, что оно применимо и к проблемам безопасности исключений; принцип одного действия ценен сам по себе.

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

Теперь, после всего сказанного, перед нами встает вопрос: когда и какую гарантию следует использовать? Вот правило, которому следует стандартная библиотека С+ + и которое вы с успехом можете применять в собственных программах.

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

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

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



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [ 23 ] 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85