Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Не підтверджено.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
3.08 Mб
Скачать
  1. Основні особливості оброблення виняткових ситуацій

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

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

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

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

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

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

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

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

}

catch(aType arg) {

II catch-блок (обробник винятків типу аТуре)

}

catch(bType arg) {

II catch-блок (обробник винятків типу ЬТуре)

}

catch(cType arg) {

II catch-блок (обробник винятків типу сТуре)

}

II....

catch(nType arg) {

II catch-блок (обробник винятків типу пТуре)

}

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

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

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

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

throw exception;

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

Вартоа пати! Якщо у програмі забезпечується "викид" винятку, для якого не передбачено відповідну catch-настанову, то відбудеться аварійне завершення

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

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

Код програми 8.1. Демонстрація механізму оброблення винятків

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

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

int mainO

{

cout«"Початок"« endl;

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

cout«try-блоці"« endl;

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

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

}

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

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

}

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

getchO; return 0;

}

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

Початок.

У try-блоці

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

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

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

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

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

Код програми 8.2. Демонстрація не коректної роботи коду програми #include <iostream> // Для потокового введення-виведення

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

int mainO

{

cout«"Початок"« endl;

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

cout«try-блоці"« endl;

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

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

}

catch(double с) {// Перехоплення винятку типу int не відбудеться, cout«"Значення перехопленого винятку дорівнює:"; cout« с « endl;

}

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

getchO; return 0;

}

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

У try-блоці

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

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

  1. Використання функцій exit() і abort() для завершення роботи коду програми

Функції exitO і abort() входять до складу стандартної бібліотеки C++ і їх часто використовують при програмуванні мовою C++. Обидві вони забезпечують завер­шення роботи коду програми, але відбувається це по-різному.

Виклик функції exit() негайно приводить до "правильного" припинення робо­ти коду програми1. Зазвичай цей спосіб завершення роботи використовують для зупинки програми під час виникнення непоправної помилки, яка робить подальше її виконання безглуздим або небезпечним. Для використання функції exitO потріб­но залучити до програми заголовок <cstdlib>. Її прототип має такий вигляд: void exit(int status)',

Оскільки функція exitO викликає негайне завершення роботи коду програми, то вона не передає керування процесу, який її викликає, і не повертає ніякого зна­чення. Проте процесу, що її викликає, як код завершення, передається значення параметра status. За домовленістю нульове значення параметра status вказує на ус­пішне завершення роботи коду програми. Будь-яке інше його значення свідчить про те, що завершення роботи коду програми є помилковим. Для індикації успіш­ного завершення роботи можна також використовувати константу EXIT_SUCCESS, а для індикації помилки - константу EXIT_FAILURE. Ці константи визначаються у заголовку <cstdlib>.

Прототип функції abortO має такий вигляд: void abortO;

Функція abortO викликає негайне завершення роботи коду програми. Але, на відміну від функції exitO, вона не повертає операційній системі ніякої інформації про статус завершення роботи коду програми і не здійснює стандартної ("пра­вильної") послідовності дій під час зупинки програми. Для використання функції abortO потрібно залучити до програми заголовок <cstdlib>. Функцію abortO можна назвати аварійним "стоп-краном" для С++-програми. Її необхідно використовува­ти тільки після виникнення непоправної помилки.

Останнє повідомлення про аварійне завершення роботи коду програми (Abnor­mal program termination) може відрізнятися від наведеного в результатах виконання попереднього прикладу. Це залежить від використовуваного Вами компілятора. Виняток, що генерує функція, яку було викликано з try-блоку, можна перехопити цим самим try -блоком. Розглянемо, наприклад, таку цілком коректну програму.

Код програми 8.3. Демонстрація механізму генерування винятку функцією, що викликається з try-блоку #include <iostream> // Для потокового введення-виведення

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

void Xtest(int test)

{

cout«"У функції XtestO значення test дорівнює:test« endl;

if(test) throw test;

}

int mainO

{

cout«"Початок"« endl;

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

cout«"У try-блоці" « endl;

Xtest(O);