
- •Курс лекцій
- •Київ-Черкаси 20010
- •1 Об‘єктно-орієнтоване програмування
- •1.1. Складові класу
- •1. Поля
- •2. Методи
- •3. Властивості
- •1.2 Оголошення класу
- •2 Огляд палітри компонентів
- •2.1 Стандартні компоненти
- •2.2 Сторінки Additional та System
- •3 Обробка виняткових ситуацій у delphi
- •Структурна обробка виняткових ситуацій
- •Модель виняткових ситуацій у Delphi
- •Синтаксис обробки виняткових ситуацій
- •Приклади обробки виняткових ситуацій
- •Виклик виняткової ситуації
- •Доступ до екземпляра об'єкта exception
- •3.4 Визначені оброблювачі виняткових ситуацій
- •3.4.1 Виключення, що виникають при роботі з базами даних
- •4 Графічні можливості delphi
- •Олівець і кисть
- •Олівець
- •Лістинг 4.1 Стилі заповнення областей
- •Вивід тексту
- •Методи креслення графічних примітивів
- •Лістинг 4.2 Осі координат і оцифрована сітка
- •Ламана лінія
- •Лістинг 4.3 Графік функції (використання методу Polyline)
- •Лістинг 4.4 Креслення замкнутого контуру (зірки) у точці натискання кнопки миші
- •Окружність і еліпс
- •Прямокутник
- •Багатокутник
- •Лістинг 4.5. Графік функції
- •Вивід ілюстрацій
- •Лістинг 10.6 Слайд-проектор
- •Бітові образи
- •Лістинг 4.7. Використання бітових образів
- •5 Робота з базами данних в delphi
- •Властивість sql
Модель виняткових ситуацій у Delphi
Модель виняткових ситуацій у 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;
Приклади обробки виняткових ситуацій
Нижче приведені процедури 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 можна використовувати усередині оброблювача виняткової ситуації.