- Обзор
С целью поддержки структурной
обработки исключительных ситуаций (exception)
в Delphi введены новые расширения языка
Pascal. В данной статье будет дано
описание того, что из себя представляет такая обработка, почему она полезна,
будут приведены соответствующий синтаксис Object Pascal и
примеры использования исключительных ситуаций в Delphi.
- Структурная обработка исключительных
ситуаций
Структурная
обработка исключительных ситуаций -
это система, позволяющая программисту при возникновении ошибки (исключительной
ситуации) связаться с кодом программы, подготовленным для обработки такой
ошибки. Это выполняется
с помощью языковых конструкций, которые как бы “охраняют”
фрагмент кода программы и определяют обработчики ошибок, которые будут
вызываться, если что-то пойдет не так в “охраняемом”
участке кода. В данном случае понятие исключительной ситуации относится
к языку и не нужно его путать с системными исключительными ситуациями (hardware
exceptions), такими как General Protection
Fault. Эти исключительные ситуации обычно
используют прерывания и особые состояния “железа”
для обработки критичной системной ошибки;
исключительные ситуации в Delphi же
независимы от “железа”,
не используют прерываний и используются для обработки ошибочных состояний,
с которыми подпрограмма не готова иметь дело. Системные исключительные
ситуации, конечно, могут быть перехвачены и преобразованы в языковые исключительные
ситуации, но это только одно из применений языковых исключительных ситуаций.
При традиционной обработке
ошибок, ошибки, обнаруженные в процедуре обычно передаются наружу (в вызывавшую
процедуру) в виде возвращаемого значения функции, параметров или глобальных
переменных (флажков). Каждая вызывающая процедура должна проверять результат
вызова на наличие ошибки и выполнять соответствующие действия. Часто, это
просто выход еще выше, в более верхнюю вызывающую процедуру и т.д. :
функция A вызывает
B, B вызывает C, C обнаруживает
ошибку и возвращает код ошибки в B, B проверяет
возвращаемый код, видит, что возникла ошибка и возвращает код ошибки в
A, A проверяет возвращаемый код
и выдает сообщение об ошибке либо решает сделать
что-нибудь еще, раз первая попытка не удалась.
Такая “пожарная
бригада” для обработки ошибок трудоемка,
требует написания большого количества кода в котором можно легко ошибиться
и который трудно отлаживать.
Одна ошибка в коде программы
или переприсвоение в цепочке возвращаемых значений может привести к тому,
что нельзя будет связать ошибочное состояние с положением дел во внешнем
мире. Результатом будет ненормальное поведение программы, потеря данных
или ресурсов, или крах системы.
Структурная обработка исключительной
ситуации замещает ручную обработку ошибок автоматической, сгенерированной
компилятором системой уведомления. В приведенном выше примере, процедура
A установила бы “охрану”
со связанным обработчиком ошибки на фрагмент кода, в котором вызывается
B. B просто вызывает C.
Когда C обнаруживает ошибку, то создает
(raise) исключительную ситуацию.
Специальный код, сгенерированный компилятором и встроенный в Run-Time
Library (RTL) начинает поиск обработчика данной
исключительной ситуации. При поиске
“защищенного”
участка кода используется информация, сохраненная в стеке. В процедурах
C и B нет
такого участка, а в A – есть. Если
один из обработчиков ошибок, которые используются в A,
подходит по типу для возникшей в C исключительной
ситуации, то программа переходит на его выполнение. При этом, область стека,
используемая в B и C,
очищается; выполнение этих процедур
прекращается.
Если в A нет
подходящего обработчика, то поиск продолжается в более верхнем уровне,
и так может идти, пока поиск не достигнет подходящего обработчика ошибок
среди используемых по умолчанию обработчиков в RTL.
Обработчики ошибок из RTL только показывают
сообщение об ошибке и форсированно прекращают выполнение программы. Любая
исключительная ситуация, которая осталась необработанной, приведет к прекращению
выполнения приложения.
Без проверки возвращаемого
кода после каждого вызова подпрограммы, код программы должен быть более
простым, а скомпилированный код – более быстрым. При наличии исключительных
ситуаций подпрограмма B не должна содержать
дополнительный код для проверки возвращаемого результата и передачи его
в A. B ничего не должна делать для
передачи исключительной ситуации, возникшей в C,
в процедуру A – встроенная система
обработки исключительных ситуаций делает всю работу.
Данная система называется
структурной, поскольку обработка ошибок определяется областью “защищенного”
кода; такие области могут быть вложенными.
Выполнение программы не может перейти на произвольный участок кода;
выполнение программы может перейти только на обработчик исключительной
ситуации активной программы. Прочитать остальную часть записи »