Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

AlgStr / Библиотека / ЛЕКЦИИ / PZ00 / Набок Ирина

.DOC
Скачиваний:
33
Добавлен:
23.03.2015
Размер:
41.98 Кб
Скачать

Исключительные ситуации

Устойчивая программа — это такая программа, которая ведет себя корректно даже в случае ошибки.

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

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

Один из способов оповещения обратившегося — это определить спе­цифический результат, возвращаемый в случае ошибки. Напри­мер, процедура факторизации может возвратить нуль, если ее аргумент не положительное число. Однако это не очень хорошее решение. Использующий данную процедуру программист может проигнорировать эту ошибку по невнимательности. Кроме того, если каждое значение возвращаемого типа есть возможный результат процедуры, то это решение не приводит к положительному результату, так как нет значения, с помощью которого можно было бы оповестить об ошибке. Вместо того чтобы иметь одну область определения, мы разделим область определения D на некоторое число подмножеств, объеди­нение которых дает D:

D=DoU...UDn

Каждое подмножество «особо» в том смысле, что процедура ведет себя по-разному на каждом из них. Мы обеспечим оповещение, имея различные области изменения для каждого подмножества области определения и придав различ­ным случаям различные имена. Произвольно дадим случаю аргумента из Do имя «обычный». Имена для других случаев могут быть выбраны тем, кто определяет процедуру. Таким образом, имеем: do —>- обычный (ro) di ->- имя1(ri) ,Dn ->имя n(Rn)где имя1, ..., имяn — имена «исключительных» ситуаций, соот­ветствующих аргументам, принадлежащим Di,... Dn соответ­ственно. Имя1 ..., имяn называются исключительными ситуациями.

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

SIGNALS: список имен и результатов исключительных ситуаций

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

Секция effects должна определять, что приводит к вызову каждой исключительной ситуации и что делает про­цедура в каждом таком случае.

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

Исключительные ситуации следует использовать для устране­ния большинства ограничений, перечисленных в предложениях requires. Эти предложения следует оставлять только из сообра­жений эффективности или если контекст использования настолько ограничен, что мы можем быть уверены, что ограничения удов­летворяются.

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

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

Исключительные ситуации в языке Паскаль

Для обработки сбоев в программах на языке Паскаль мы за­даем некоторую процедуру, называемую failure. Эта процедура помещается в начало программы, и к ней может обращаться лю­бая другая операция в этой программе. Спецификация данной процедуры следующая:

procedure failure (s: error.msg)

modifies Выходной поток на основном устройстве вывода.

effects Печатает следующую строку на основном устройстве вывода: "Сбой. Программа окончилась из-за:" + s, а затем выполнение программы останавливается.

Аргумент при обращении должен, конечно, идентифицировать проблему и операцию, в ко­торой она произошла. Обычно тип error.msg будет объявляться как некоторый тип строк. Если в используемом языке Паскаль строки не поддерживаются, аргумент может быть представлен как упакованный массив символов.

function searchi (var a: int. array; х: integer; var i: integer):searchi _exceptions

modifies i

effects Если переменная х находится в массиве а, то индекс i устанавли­вается таким, что а [i] = х, и возвращается значение ok; в противном случае возвращается значение not-in.

где searchi-exceptions является вычисляемым типом type searchi_exceptions == (ok, not-in)

Отметим, что функция searchi имеет третий аргумент — параметр i с типом var. Эта переменная используется для получения ре­зультата в нормальном случае.

По соглашению все обращения к этой функции мы вставляем в предложение case следующим образом:

case searchi (а, х, i) of

ok: a[i]:=a[i]+l;

not-in: write («Элемент не найден»)

end

Предложение case должно иметь ветвь, соответствующую каждому значению, которое может быть возвращено функцией. (Если возможны только две альтернативы, как в случае с функцией searchi, результат мог бы иметь булевский тип, а не вычисляе­мый тип, и оператор if мог бы использоваться вместо предложе­ния case.)

Этот подход имеет несколько недостатков. Неудобно, что функция searchi модифицирует параметр с типом var вместо выдачи индекса, поскольку мы не сможем тогда ее использовать в таких выражениях, как a [search I (a, x)] Более того, функция searchi не так надежна при использовании, как процедура search. На­пример, предположим, что мы решили добавить еще одно значе­ние в тип searchi_exceptions. В соответствии с нашими соглаше­ниями надо добавить еще одну ветвь к каждому предложению case, в котором имеется обращение к функции searchi. Если, од­нако, это не будет сделано, то не возникнет ни ошибки во время компиляции, ни ошибок во время счета. (В языке Паскаль, если переключатель в предложении case не соответствует никакой из ветвей, программа продолжает выполнение g предложения, сле­дующего за предложением case.)