Помощничек
Главная | Обратная связь


Археология
Архитектура
Астрономия
Аудит
Биология
Ботаника
Бухгалтерский учёт
Войное дело
Генетика
География
Геология
Дизайн
Искусство
История
Кино
Кулинария
Культура
Литература
Математика
Медицина
Металлургия
Мифология
Музыка
Психология
Религия
Спорт
Строительство
Техника
Транспорт
Туризм
Усадьба
Физика
Фотография
Химия
Экология
Электричество
Электроника
Энергетика

Приклади обробки виняткових ситуацій




Нижче приведені процедури A,B і C, що обговорювалися раніше, втілені в новому синтаксисі Object Pascal:

type

ESampleError = class(Exception);

var

ErrorCondition: Boolean;

procedure C;

begin

writeln('Enter C');

if (ErrorCondition) then

begin

writeln('Raising exception in C');

raise ESampleError.Create('Error!');

end;

writeln('Exit C');

end;

procedure B;

begin

writeln('enter B');

C;

writeln('exit B');

end;

procedure A;

begin

writeln('Enter A');

try

writeln('Enter A''s try block');

B;

writeln('After B call');

except

on ESampleError do

writeln('Inside A''s ESampleError handler');

on ESomethingElse do

writeln('Inside A''s ESomethingElse handler');

end;

writeln('Exit A');

end;

begin

writeln('begin main');

ErrorCondition := True;

A;

writeln('end main');

end.

 

При ErrorCondition = True програма видасть:

 

begin main

Enter A

Enter A's try block

enter B

Enter C

Raising exception in C

Inside A's ESampleError handler

Exit A

end main

Можливо вас здивувала декларація типу 'ESampleError =class' замість '=object'; це ще одне нове розширення мови. Delphi уводить нову модель об'єктів, доступну через декларацію типу '=class'. Опис нової об'єктної моделі дається в інших уроках. Тут же досить сказати, що виняткові ситуації (exceptions) є класами, частиною нової об'єктної моделі.

Процедура C перевіряє наявність помилки (у нашому випадку це значення глобальної перемінної) і, якщо вона є (а це так), C викликає(raise) виняткову ситуацію класу ESampleError.

Процедура A поміщає частину коду в блок try..except. Перша частина цього блоку містить частину коду, аналогічно конструкції begin..end. Ця частина коду завершується ключовим словом except, далі випливає один чи більш оброблювачів виняткових ситуацій on xxxx do yyyy, далі може бути включений необов'язковий блок else, уся конструкція закінчується end;. У конструкції, що призначає визначену обробку для конкретної виняткової ситуації (on xxxx do yyyy), після резервного слова on указується клас виняткової ситуації, а після do випливає власне код обробки даної помилки. Якщо виникла виняткова ситуація підходить по типу до зазначеного послу on, то виконання програми переходить сюди (на код після do). Виняткова ситуація підходить у тім випадку, якщо вона того ж класу, що зазначено в on, або є його нащадком. Наприклад, у випадку on EFileNotFound оброблятися буде ситуація, коли файл не знайдений. А у випадку on EFileIO - усі помилки при роботі з файлами, у тому числі і попередня ситуація. У блоці else обробляються всі помилки, не оброблені до цього.

Приведені в прикладі процедури містять код (рядок з writeln), що відображає шлях виконання програми. Коли C викликає exception, програма відразу переходить на оброблювач помилок у процедурі A, ігноруючи частину коду, що залишилася, у процедурах B і C.

Після того, як знайдений придатний оброблювач помилки, пошук закінчується. Після виконання коду оброблювача, програма продовжує виконуватися з оператора, що коштує після слова end блоку try..except (у прикладі - writeln('Exit A')).

Конструкція try..except підходить, якщо відомо, який тип помилок потрібно обробляти в конкретній ситуації. Але що робити, якщо потрібно виконати деякі дії в будь-якому випадку, відбулася чи помилка ні? Це той випадок, коли знадобиться конструкція try..finally.

Розглянемо модифіковану процедуру B:

procedure NewB;

var

P: Pointer;

begin

writeln('enter B');

GetMem(P, 1000);

C;

FreeMem(P, 1000);

writeln('exit B');

end;

Якщо C викликає виняткову ситуацію, то програма вже не повертається в процедуру B. А що ж з тими 1000 байтами пам'яті, захопленими в B? Рядок FreeMem(P,1000) не виконається і Ви втратите шматок пам'яті. Як це виправити? Потрібно ненав'язливо включити процедуру B у процес, наприклад:

procedure NewB;

var

P: Pointer;

begin

writeln('enter NewB');

GetMem(P, 1000);

try

writeln('enter NewB''s try block');

C;

writeln('end of NewB''s try block');

finally

writeln('inside NewB''s finally block');

FreeMem(P, 1000);

end;

writeln('exit New');

end;

Якщо в A помістити виклик New замість B, то програма виведе повідомлення в такий спосіб:

begin main

Enter A

Enter A's try block

enter NewB

enter NewB's try block

Enter C

Raising exception in C

inside NewB's finally block

Inside A's ESampleError handler

Exit A

end main

Код у блоці finally виконається при будь-якій помилці, що виникла у відповідному блоці try. Він же виконається й у тому випадку, якщо помилки не виникло. У будь-якому випадку пам'ять буде звільнена. Якщо виникла помилка, то спочатку виконується блок finally, потім починається пошук придатного оброблювача. У штатній ситуації, після блоку finally програма переходить на наступне пропозицію після блоку.

Чому виклик GetMem не поміщений усередину блоку try? Цей виклик може закінчитися невдало і викликати exception EOutOfMemory. Якщо це відбулося, то FreeMem спробує звільнити пам'ять, що не була розподілена. Коли ми розміщаємо GetMem поза ділянкою, що захищається, то припускаємо, що B зможе одержати потрібну кількість пам'яті, а якщо ні, те більш верхня процедура одержить повідомлення EOutOfMemory.

А що, якщо потрібно в B розподілити 4 області пам'яті за схемою ус-чи-нічого? Якщо перші дві спроби удалися, а третя провалилася, то як звільнити захоплену область пам'ять? Можна так:

procedure NewB;

var

p,q,r,s: Pointer;

begin

writeln('enter B');

P := nil;

Q := nil;

R := nil;

S := nil;

try

writeln('enter B''s try block');

GetMem(P, 1000);

GetMem(Q, 1000);

GetMem(R, 1000);

GetMem(S, 1000);

C;

writeln('end of B''s try block');

finally

writeln('inside B''s finally block');

if P <> nil then FreeMem(P, 1000);

if Q <> nil then FreeMem(Q, 1000);

if R <> nil then FreeMem(R, 1000);

if S <> nil then FreeMem(S, 1000);

end;

writeln('exit B');

end;

Установивши спершу покажчики в NIL, далі можна визначити, чи успішно пройшов виклик GetMem.

Обидва типи конструкції try можна використовувати в будь-якім місці, допускається вкладеність будь-якої глибини. Виняткову ситуацію можна викликати усередині оброблювача помилки, конструкцію try можна використовувати усередині оброблювача виняткової ситуації.

 




Поиск по сайту:

©2015-2020 studopedya.ru Все права принадлежат авторам размещенных материалов.