Опубликован: 17.10.2005 | Уровень: специалист | Доступ: платный
Лекция 12:

Когда контракт нарушается: обработка исключений

Аннотация: Нравится это или нет, но не стоит притворяться, несмотря на все статические предосторожности, некоторые неожиданные и нежелательные события рано или поздно возникнут при одном из выполнений системы. Такие ситуации известны как исключения, и нужно должным образом уметь справляться с ними.

Базисные концепции обработки исключений

Литература по обработке исключений зачастую не очень точно определяет, что вызывает исключение. Как следствие, механизм исключений, представленный в таких языках программирования как PL/I и Ada, часто неправильно используется: вместо того, чтобы резервироваться только для истинно чрезвычайных ситуаций, они заканчивают службу как внутрипрограммные инструкции goto, нарушающие принцип Защищенности.

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

Отказы

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

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

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

Такие ситуации будем называть отказом (failure).

Определения: успех, отказ

Вызов программы успешен, если он завершается в состоянии, удовлетворяющем контракту. Вызов завершается отказом, если он не успешен.

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

Исключения

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

Определение: исключение

Исключение - событие периода выполнения, которое может стать причиной отказа программы.

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

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

Источники исключений

Исключения можно классифицировать, разделив их на категории.

Определение: исключительные ситуации

Исключения могут возникать при выполнении программы r в результате следующих ситуаций.

  1. Попытка квалифицированного вызова a.f и обнаружение, что a = Void.
  2. Попытка присоединить значение Void к развернутой ( expanded ) цели.
  3. Выполнение невозможной или запрещенной операции, обнаруживаемое аппаратно или операционной системой.
  4. Вызов программы, приводящей к отказу.
  5. Предусловие r не выполняется на входе.
  6. Постусловие r не выполняется на выходе.
  7. Инвариант класса не выполняется на входе или выходе.
  8. Инвариант цикла не выполняется в результате инициализации в предложении from или после очередной итерации тела цикла.
  9. Итерация тела цикла не уменьшает вариант цикла.
  10. Не выполняется утверждение инструкции check.
  11. Выполнение инструкции, явно включающей исключение.

Случай (1) отражает одно из основных требований к использованию ссылок: вызов a.f имеет смысл, когда к a присоединен объект, другими словами, когда a не void. Это обсуждалось в "Динамические структуры: объекты" при рассмотрении динамической модели.

Случай (2) также имеет дело с void значениями. Напомним, что "присоединение" ( attachment ) покрывает присваивание и передачу аргументов, имеющих одинаковую семантику. В разделе "Гибридное присоединение" "Динамические структуры: объекты" отмечалась возможность присваивания ссылки развернутой цели, в результате чего происходит копирование объекта. Но это предполагает существование объекта, но если источник void, то присоединение вызовет исключение.

Случай (3) следствие сигналов, посылаемых приложению операционной системой.

Случай (4) возникает при отказе программы, как результат возникновения в ней исключения, с которым она не смогла справиться. Более подробно это будет рассмотрено ниже, но пока обратите внимание на правило, вытекающее из (4):

Отказы и исключения

Отказ программы - причина появления исключения в вызывающей программе.

Случаи (5)-(10) могут встретиться только при мониторинге утверждений, включенных на соответствующем уровне: assertion (require) для (5), assertion (loop) для (8) и (9) и так далее.

Случай (11) предполагает вызов процедуры raise, выбрасывающей (зажигающей) исключения. Такая процедура будет рассмотрена чуть позднее.

Ситуации отказа

Рассматривая список возможных исключений, полезно определить, когда может встретиться отказ (причина исключения у вызывающей программы):

Определение: случаи отказа

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

Определения отказа и исключения взаимно рекурсивны: отказ возникает из-за появления исключений, а одна из причин исключения - отказ при вызове программы (случай (4)).

Александр Шалухо
Александр Шалухо
Анатолий Садков
Анатолий Садков

При заказе pdf документа с сертификатом будет отправлен только сертификат или что-то ещё?

Алексей Щербанов
Алексей Щербанов
Россия, г. Оренбург
Ксения Маковецкая
Ксения Маковецкая
Россия, Москва, МГЮА им. О.Е. Кутафина, 2014