Библиотека программиста

«Очень важно не прерывать вопросов. Любопытство имеет свое право на существование»

Альберт Эйнштейн

Главная страница > Язык Object Pascal > 31. Введение в обработку исключительных ситуаций в Delphi

31. Введение в обработку исключительных ситуаций в Delphi

Структурная обработка исключительных ситуаций - это система, позволяющая программисту при возникновении ошибки (исключительной ситуации) выполнить код программы, подготовленный для обработки такой ошибки. Это выполняется с помощью языковых конструкций, которые как бы "охраняют” фрагмент кода программы и определяют обработчики ошибок, которые будут вызываться, если что-то пойдет не так в “охраняемом” участке кода. В данном случае понятие исключительной ситуации относится к языку и не нужно его путать с системными исключительными ситуациями (hardware exceptions), такими как General Protection Fault. Эти исключительные ситуации обычно используют прерывания и особые состояния аппаратуры для обработки критичной системной ошибки. Исключительные ситуации в Delphi независимы от “железа”, не используют прерываний и используются для обработки таких ошибочных состояний, которые в программе не предусмотрены. Системные исключительные ситуации, конечно, могут быть перехвачены и преобразованы в языковые исключительные ситуации, но это только одно из применений языковых исключительных ситуаций.

Механизм обработки исключительных ситуаций (ошибок), впервые реализованный в Windows NT и затем внедренный во все операционные системы Microsoft и языковые процессоры, позволяет программисту избавиться от рутинных операций по многочисленным проверкам и реакции на их результаты.

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

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

Структурная обработка исключительной ситуации заменяет ручную обработку ошибок автоматической, сгенерированной компилятором. В приведенном выше примере, процедура A установила бы “охрану” на фрагмент кода, в котором вызывается B. B просто вызывает C. Когда C обнаруживает ошибку, то создает (raise) исключительную ситуацию. Специальный код, сгенерированный компилятором, начинает поиск обработчика данной исключительной ситуации. При поиске “защищенного” участка кода используется информация, сохраненная в стеке. В процедурах C и B нет такого участка, а в A - есть. Если один из обработчиков ошибок, которые используются в A, подходит по типу для возникшей в C исключительной ситуации, то программа переходит на его выполнение. При этом область стека, используемая в B и C, очищается и выполнение этих процедур прекращается.

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

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

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

Модель исключительных ситуаций в Object Pascal является невозобновляемой (non-resumable). Это значит, что при возникновении исключительной ситуации невозможно вернуться в точку, где она возникла, для продолжения выполнения программы (это позволяет сделать возобновляемая – resumable – модель). Невозобновляемые исключительные ситуации разрушают стек, поскольку они сканируют его в поисках обработчика. В возобновляемой модели необходимо сохранять стек, состояние регистров процессора в точке возникновения ошибки и выполнять поиск обработчика и его выполнение в отдельном стеке. Возобновляемую систему обработки исключительных ситуаций гораздо труднее создать и применять, нежели невозобновляемую.

Синтаксис обработки исключительных ситуаций.

Новое ключевое слово, добавленное в язык Object Pascal - try. Оно используется для обозначения первой части защищенного участка кода. Существует два типа защищенных участков:

· try … except

· try … finally

Первый тип используется для обработки исключительных ситуаций. Его синтаксис:

try

Statement 1;

Statement 2;

...

except

on Exception1 do Statement;

on Exception2 do Statement;

...

else

Statements; {default exception-handler}

end;

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

try

Statement1;

Statement2;

...

finally

Statements; { These statements always execute }

end;

Классы ИС.

В модуле Sysutils определен класс Exception - базовый класс-предок всех обработчиков исключительных ситуаций. Кроме того, в этом модуле определено также много других классов, производных от Exception, например:

EIntError - предок исключений, случающихся при выполнении целочисленных операций.

EMathError - предок исключений, случающихся при выполнении операций с плавающей точкой.

EInOutError - происходит при ошибках ввода/вывода при включенной директиве {$I+}.

О методах этих классов.

Программист может определить свой собственный класс ИС, производный от любого другого, например:

type

EMyException = class(Exception);

Отличительной особенностью при работе с классами ИС является то, что объект этого класса описывать не нужно и нельзя, но создавать его можно и можно также получить доступ к экземпляру этого класса (объекту), но несколько необычным способом. Кроме того, для объекта ИС не нужно вызвать деструктор, так как это делается автоматически после завершения обработки ИС в операторе on.

Оператор вызова ИС raise.

Помимо оператора try в Object Pascal имеется оператор вызова ИС, который имеет такой формат:

raise object at address;

В этом операторе можно опустить object, at address или оба параметра. Если опущен object, повторно вызывается текущая ИС. Address – это указатель, и обычно он указывает на процедуру или функцию. Address используется для того, чтобы вызвать ИС в точке, расположенной в стеке ранее, а не в текущей точке программы. Обычно этот оператор используется так:

raise EcxeptionClass.Create(‘Описание ошибки’);

В этом примере создается объект ИС некоторого класса EcxeptionClass и этот объект будет существовать до конца обработки ИС, т.е. до завершения оператора on.





<< Предыдущая статья
«30. Ссылки на класс»
Следующая статья >>
32. Примеры обработки исключительных ситуаций