Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
+ООП_Навч_посібник.doc
Скачиваний:
7
Добавлен:
01.07.2025
Размер:
6.58 Mб
Скачать

18.1. Основи оброблення виняткових ситуацій

Оброблення винятків – це системні засоби, за допомогою яких програма може справитися з помилками часу виконання.

Керування С++-механізмом оброблення винятків тримається на трьох ключових словах: try, catch і throw. Вони утворюють взаємозв'язану підсистему, у якій використання одного з них припускає застосування іншого. Спершу буде корисно отримати загальне представлення про роль, яку вони відіграють під час оброблення виняткових ситуацій.

18.1.1. Системні засоби оброблення винятків

Якщо стисло, то їх робота полягає в наступному. Програмні настанови, які Ви вважаєте за потрібне проконтролювати на предмет винятків, поміщаються в try-блок. Якщо виняток (тобто помилка) таки виникає у цьому блоці, то він дає знати про себе шляхом викидання певного роду інформації (за допомогою ключового слова throw). Цей викинутий виняток можна перехопити програмним шляхом за допомогою catch-блоку і оброблений відповідним чином. А зараз сказане постараємося розглянути грунтовніше.

Настанова throw генерує виняток, який перехоплюється catch-настановою.

Отже, програмний код, у якому можливе виникнення виняткових ситуацій, повинен виконуватися у межах try-блоку. Будь-яка функція, що викликається з цього try-блоку, також піддається контролю. Винятки, які можуть бути викинуті контрольованим кодом, перехоплюються catch-настановою, безпосередньо наступною за try-блоком, у якому фіксуються ці "викиди" винятків. Загальний формат try- і catch-блоків має такий вигляд:

try {

// try-блок (блок коду програми, що підлягає перевірці

// на наявність помилок)

}

catch(aType arg) {

// catch-блок (обробник винятків типу aType)

}

catch(bType arg) {

// catch-блок (обробник винятків типу bType)

}

catch(cType arg) {

// catch-блок (обробник винятків типу cType)

}

//....

catch(nType arg) {

// catch-блок (обробник винятків типу nType)

}

Блок try повинен містити програмний код, який, на Вашу думку, повинен перевірятися на предмет виникнення помилок. Цей блок може містити тільки декілька настанов деякої функції або охоплювати весь код функції main() (у цьому випадку, по суті, "під ковпаком" системи оброблення винятків знаходитиметься вся програма).

Після "викиду" виняток перехоплюється відповідною настановою catch, яка виконує його оброблення. З одним try-блоком може бути пов'язана не одна, а декілька catch-настанов. Яка саме з них буде виконана, визначається типом винятку. Іншими словами, буде виконана та catch-настанова, тип винятку якої (тобто тип даних, що задається в catch-настанові) збігається з типом згенерованого винятку (а всі інші будуть проігноровані). Після перехоплення винятку параметр arg прийме його значення. Таким шляхом можуть перехоплюватися дані будь-якого типу, в т.ч. об'єкти класів, що були створені програмістом.

Щоб виняток було перехоплено, необхідно забезпечити його "викид" в try-блоці.

Загальний формат настанови throw має такий вигляд:

throw exception;

У цьому записі за допомогою елемента exception задається виняток, що згенерується настановою throw. Якщо цей виняток підлягає перехопленню, то настанова throw повинна бути виконана або в самому блоці try, або в будь-якій функції, які викликається з нього (тобто прямо або опосередковано).

Варто знати! Якщо у програмі забезпечується "викид" винятку, для якого не передбачена відповідна catch-настанова, то відбудеться аварійне завершення роботи програми, що викликається стандартною бібліотечною функцією terminate(). За замовчуванням функція terminate() викликає функцію abort() для зупинки програми, але при бажанні можна визначити власний обробник для її завершення. За подробицями щодо оброблення цієї ситуації необхідно звернутися до документації, що додається до Вашого компілятора.

Розглянемо простий приклад оброблення винятків засобами мови C++.

Код програми 18.1. Простий приклад оброблення винятків

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

int main()

{

cout << "Початок.\n";

try { // Початок try-блоку

cout << "B try-блоці\n";

throw 99; // Генерування помилки

cout << "Ця настанова не буде виконана.";

}

catch(int izm) { // Перехоплення помилки

cout << "Значення перехопленого винятку дорівнює: "

<< izm << "\n";

}

cout << "Кінець програми";

getch(); return 0;

}

У процесі виконання ця програма відображає на екрані такі результати:

Початок.

У try-блоці

Значення перехопленого винятку дорівнює: 99

Кінець програми

Розглянемо уважно код цієї програми. Як бачите, тут try-блок містить три настанови, а настанова catch(int izm) призначена для оброблення винятку цілочисельного типу. У цьому try-блоці виконуються тільки дві з трьох настанов: cout і throw. Після генерування винятку керування передається catch-виразу, при цьому виконання try-блоку припиняється. Необхідно розуміти, що catch-настанова не викликається, а просто з неї продовжується виконання програми після "викиду" винятку. Стек програми автоматично налаштовується відповідно до ситуації, що створилася. Тому cout-настанова, що є наступною після throw-настанови, ніколи не виконається.

Після виконання catch-блоку керування програмою передається настанові, що є наступною за цим блоком. Тому Ваш обробник винятків повинен виправити помилку, що викликала його виникнення, щоб програма могла нормально продовжити виконання. У випадках, коли помилку виправити не можна, catch-блок зазвичай завершується зверненням до функцій exit() або abort()(див. розд. 18.1.2).

Як ми вже зазначали вище, тип винятку повинен збігатися з типом, заданим у catch-настанові. Наприклад, якщо в попередній програмі тип int, який було вказано в catch-виразі, замінити типом double, то виняток перехоплено не буде і відбудеться аварійне завершення роботи програми. Ось як виглядають наслідки внесення такої зміни.

Код програми 18.2. Цей приклад працювати не буде

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

int main()

{

cout << "Початок.\n";

try { // Початок try-блоку

cout << "У try-блоці\n";

throw 99; // генерування помилки

cout << "Ця настанова не буде виконана.";

}

catch(double izm) { // Перехоплення винятку типу int не відбудеться.

cout << "Значення перехопленого винятку дорівнює: ";

cout << izm << "\n";

}

cout << "Кінець програми";

getch(); return 0;

}

Такі результати виконання цієї програми пояснюються тим, що винятки цілочисельного типу не перехоплюється настановою catch(double izm).

Початок.

У try-блоці

Ця настанова не буде виконана.