Привет, Гость! Регистрация RSS
Пятница, 19.04.2024
Главная » Статьи » Основные статьи сайта

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

С целью поддержки структурной обработки исключительных ситуаций (exception) в язык Object Pascal были введены расширения начиная с Delphi версии 1.0, но только начиная с Delphi 2.0 исключения стали частью Win32 API

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

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

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

Традиционная обработка ошибок

При традиционной обработке ошибок, ошибки, обнаруженные в процедуре обычно передаются наружу (в вызывавшую процедуру) в виде возвращаемого значения функции, параметров или глобальных переменных (флажков). Каждая вызывающая процедура должна проверять результат вызова на наличие ошибки и выполнять соответствующие действия. Часто, это просто выход еще выше, в более верхнюю вызывающую процедуру и т.д. : функция 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 - встроенная система обработки исключительных ситуаций делает всю работу. 

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

Модель исключительных ситуаций в Delphi

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

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

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

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

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

try..except
try..finally

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

try
  Оператор1;
  Оператор2;
  ...
except
  on Ошибка1 do оператор;
  on Ошибка2 do оператор;
  ...
else
  операторы; {обработчик остальных ошибок}
end;

Блок try..finally

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

try
  Оператор1;
  Оператор2;
  ...
finally
  Операторы;  { Эти операторы всегда выполняются }
end;

Доступ к экземпляру объекта Exception

При вызове исключительной ситуации (raise) автоматически создается экземпляр соответствующего класса, который и содержит информацию об ошибке. Обработчик может получить доступ к этому объекту используя следующий синтаксис:

procedure NewA;
begin
writeln('Enter A');
try
writeln('Enter A''s try block');
B;
writeln('After B call');
except
on E: ESampleError do writeln(E.Message);
on ESomethingElse do
writeln('Inside A''s ESomethingElse handler');
end;
writeln('Exit A');
end;

on E: ESampleError do writeln(E.Message);

Пример демонстрирует еще одно новшество в языке Object Pascal - создание локальной переменной. В примере локальной переменной является E - это экземпляр класса ESampleError, который был создан в процедуре C в момент вызова исключительного состояния. Переменная E доступна только внутри блока do. Свойство Message объекта E содержит сообщение, которое было передано в конструктор Create в процедуре C. 

Еще один способ доступа к объекту исключительной ситуации  - использовать функцию ExceptionObject

on ESampleError do
  writeln(ESampleError(ExceptionObject).Message);

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

  • Exception - базовый класс-предок всех обработчиков исключительных ситуаций.
  • EAbort - "скрытое" исключение. Используйте его тогда, когда хотите прервать тот или иной процесс с условием, что пользователь программы не должен видеть сообщения об ошибке. Для повышения удобства использования в модуле SysUtils предусмотрена процедура Abort
  • EConvertError - происходит в случае возникновения ошибки при выполнении функций StrToInt и StrToFloat, когда конвертация строки в соответствующий числовой тип невозможна.
  • EInOutError - происходит при ошибках ввода/вывода при включенной директиве {$I+}.
  • EInvalidCast - происходит при попытке приведения переменных одного класса к другому классу, несовместимому с первым (например, приведение переменной типа TListBox к TMemo).
  • EInvalidGraphic - вызывается при попытке передачи в LoadFromFile файла, несовместимого графического формата.
  • EInvalidGraphicOperation - вызывается при попытке выполнения операций, неприменимых для данного графического формата (например, Resize для TIcon)
  • EIntError - предок исключений, случающихся при выполнении целочисленных операций.
    • EDivByZero - вызывается в случае деления на ноль, как результат RunTime Error 200.
    • EIntOverflow - вызывается при попытке выполнения операций, приводящих к переполнению целых переменных, как результат RunTime Error 215 при включенной директиве {$Q+}.
    • ERangeError - вызывается при попытке обращения к элементам массива по индексу, выходящему за пределы массива, как результат RunTime Error 201 при включенной директиве {$R+}.
  • EInvalidObject - реально нигде не используется, объявлен в Controls.pas.
  • EInvalidOperation - вызывается при попытке отображения или обращения по Windows-обработчику (handle) контрольного элемента, не имеющего владельца (например, сразу после вызова MyControl:=TListBox.Create(...) происходит обращение к методу Refresh).
  • EInvalidPointer - происходит при попытке освобождения уже освобожденного или еще неинициализированного указателя, при вызове Dispose(), FreeMem() или деструктора класса.
  • EListError - вызывается при обращении к элементу наследника TList по индексу, выходящему за пределы допустимых значений (например, объект TStringList содержит только 10 строк, а происходит обращение к одиннадцатому).
  • EMathError - предок исключений, случающихся при выполнении операций с плавающей точкой.
    • EInvalidOp - происходит, когда математическому сопроцессору передается ошибочная инструкция. Такое исключение не будет до конца обработано, пока Вы контролируете сопроцессор напрямую из ассемблерного кода.
    • EOverflow - происходит как результат переполнения операций с плавающей точкой при слишком больших величинах. Соответствует RunTime Error 205.
    • Underflow - происходит как результат переполнения операций с плавающей точкой при слишком малых величинах. Соответствует RunTime Error 206.
    • EZeroDivide - вызывается в результате деления на ноль.
  • EMenuError - вызывается в случае любых ошибок при работе с пунктами меню для компонент TMenu, TMenuItem, TPopupMenu и их наследников.
  • EOutlineError - вызывается в случае любых ошибок при работе с TOutLine и любыми его наследниками.
  • EOutOfMemory - происходит в случае вызовов New(), GetMem() или конструкторов классов при невозможности распределения памяти. Соответствует RunTime Error 203.
  • EOutOfResources - происходит в том случае, когда невозможно выполнение запроса на выделение или заполнение тех или иных Windows ресурсов (например таких, как обработчики - handles).
купить стабилизатор напряжения для дома можно на сайте http://phantom-stab.ru/

Пример

Var
  i: Integer;
  R: Real;
begin
  try
    R := i / 0;
    if r > 0 then
      beep;
  except
    on e: EZeroDivide do
      Application.HandleException(Sender);
  end;
end;

Когда исключительная ситуация прошла через все блоки try except которые защищали участок кода в котором она произошла и нигде не было обработано, приложение вызывает метод Application.HandleException(Sender), который проводит стандартную обработку исключительной ситуации путём вывода диалогового окна с сообщением об ошибке.

property OnException: TExceptionEvent;
type TExceptionEvent = procedure (Sender: TObject; E: Exception) of object;

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

procedure TForm1.MyException(Sender: TObject; E: Exception);
Var
  F: TextFile;
begin
  AssignFile(F, 'log.txt');
  Append(F);
  WriteLn(F, E.Message);
  CloseFile(F);
  ShowMessage(E.Message);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
  Application.OnException := MyException;
end;

P.S. Самые свежие новости Украины представлены на http://www.onsmi.net/ - политика, экономика, спорт, интернет и многое другое.


Нравится
Категория: Основные статьи сайта | Добавил: Dark_Green (21.12.2013)
Просмотров: 6047 | Теги: Finally, ошибка, обработка исключительных ситуаций, Try, exception, except | Рейтинг: 5.0/4

Другие статьи
»
Формы со вкладками. Оформление приложений с помощью многостраничных панелей. (0)
»
Функция Pars(); (1)
»
Рисование при выполнении программы (0)
»
Разновидности форм (0)
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]