Иногда, під час роботи програм, зустрічаються ситуації які перешкоджають подальшої нормальної їх роботи. Наприклад при розподілі числа на нуль, програма завершить роботу не дивлячись на те, скільки користувач працював в програмі, і який обсяг даних вніс. Програма просто закриється.
І уявіть, якщо до цього користувач вносив в програму дані кілька годин і проводив розрахунки. При такому аварійному закритті програми всі ці дані і розрахунки пропадуть. Согласитесь – не дуже приємно. Також може зустрітися така ситуація, коли програма намагається відкрити недоступний в цей момент файл, або запросити більше, ніж є пам'яті.
Такого роду ситуації програмістам треба намагатися передбачити і будувати програми так, щоб вони могли гнучко реагувати, а не аварійно закриватися. У моїй улюбленій книзі Язык программирования C . Лекции и упражнения автора З. Прата, дано таке визначення винятків в С ++:
Щоб вам не складно було зрозуміти механізм роботи винятків в С ++, розглянемо їх на простому прикладі. У ньому ми передбачаємо той випадок, що в якийсь момент під час розрахунків програми, може зустрітися розподіл числа на 0. Наберіть і скомпілюйте код, розташований нижче. Щоб переконатися в тому, як реагує програма на таку ситуацію, внесіть число 0 в змінну num2 (вона виступає делителем в прикладі).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include <iostream>; using namespace std; int main() { setlocale(LC_ALL, "rus"); int num1; int num2; int var = 3; // управляющая переменная для while while (var != 0) { cout << "Введите число num1: "; cin >> num1; cout << "Введите число num2: "; cin >> num2; cout << "num1 + num2 = " << num1 + num2 << endl; cout << "num1 / num2 = " << num1 / num2 << endl; cout << "num1 - num2 = " << num1 - num2 << endl; cout << "=================================" << endl << endl; var--; } cout << "Конец работы программы!" << endl << endl; return 0; } |
Так як змінна var дорівнює 3, цикл while, в нормальній ситуації, повинен відпрацювати три рази. З кожним кроком циклу varзменшується на одиницю за допомогою декремент. Але так як ми відразу внесли значення 0 в зміннуnum2, програма не пройде до кінця навіть перший крок циклу. вона перерветься.
У наступному лістингу, ми виправимо це упущення – додамо кілька компонентів, які допоможуть зреагувати на цю ситуацію без переривання роботи програми. А именно:
- блок пробувати или пробувати-блок(спроба, зразок);
- генератор виключення– блоккидати(обробити, запустити);
- обробник виключення, який його перехоплює-команда виловити (зловити, ловити)
Як працює виняток? – Програміст прописує в коді (впробувати-блоці) конкретна умова, що якщо змінна num2 МАТИМЕ 0, то в такому випадку необхідно генерувати виняток вкидати. Далі, то що згенерувавкидати, перехоплюєвиловити-блок (у вигляді параметра функції) і програма виконає той код, який прописаний в цьому блоці.
Приклад:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #include <iostream>; using namespace std; int main() { setlocale(LC_ALL, "rus"); int num1; int num2; int var = 3; while (var != 0) { cout << "Введите число num1: "; cin >> num1; cout << "Введите число num2: "; cin >> num2; cout << "num1 + num2 = " << num1 + num2 << endl; cout << "num1 / num2 = "; try // тут располагается код, который потенциально может вызвать ошибку { if (num2 == 0) { throw 999; // генерировать целое число 999 } cout << num1 / num2 << endl; } catch (int thr)// сюда передастся число, которое сгенерировал throw { cout << "Ошибка №" << thr << " - деление на 0!!!" << endl; } cout << "num1 - num2 = " << num1 - num2 << endl; cout << "=================================" << endl << endl; var--; } cout << "Программа завершила работу!" << endl << endl; return 0; } cout << "Программа завершила работу!" << endl << endl; return 0; } |
зрозуміти в деталях. У рядках 21-29 знаходиться блок пробувати. У ньому необхідно розміщувати той код, який може призвести до незворотних помилок. Ще до арифметичного виразу розподілу задаємо умову: еслиnum2 дорівнюватиме 0, то нехайкидати генерує число 999 (наприклад).
В тому випадку, відразу після генерації числа, подальші команди в блоціпробувати виконуватися вже не будуть, а саме число “впаде” в блоквиловити (у вигляді параметра). Далі виконається то, що зазначено в блоцівиловити – в нашем случае, це буде повідомлення про помилку:
cout << "Помилка №" << Чет << " - поділ на 0!!!" << endl;
і програма буде виконувати наступні команди. В тому випадку, якщо числоnum2 != 0, то throw нічого не генерує і виловити-блок не спрацює.
подивіться тепер, як відреагує програма, якщо ви введетеnum2 рівне нулю. запускайте програму.
як бачимо, там де могла статися помилка і дострокове завершення програми, ми побачили повідомлення Помилка №999 – поділ на 0!!! Программа “перескочила” через операцію ділення на 0 і виконалавиловити-блок.
Щоб ви краще зрозуміли, як значення генеруєтьсякидати перехоплюєвиловити-блок, замініть код в рядках 21 – 33 на цей:
1 2 3 4 5 6 7 8 9 10 11 12 | try { if (num2 == 0) { throw "Ошибка - деление на 0!!!!"; // генерируется строка cout << num1 / num2 << endl; } } catch (char *str) // строку перехватывает catch-блок { cout << str << endl; } |
У цьому прикладі, если num2 дорівнює 0,кидати генерує рядок, а не число. Строка “падає” ввиловити-блок і виводиться на екран.
Розглянемо ще такий приклад, коли виняток генерується в функции, яка ділить одне число на інше:
1 2 3 4 5 6 7 8 | int delenie(int n1, int n2) { if (n2 == 0) { throw 99; } return n1 / n2; }; |
Щоб виняток спрацювало правильно, цю функцію треба викликати в блоціпробувати:
1 2 3 4 5 6 7 8 9 | try { cout << delenie(7, 0); cout << endl; } catch (int thr) { cout << "Ошибка №" << thr << " Деление на 0!!!" << endl; } |
виловити перехопить число 99, а розподіл на 0 не відбудуться.
Основное, що потрібно запам'ятати про винятки в С ++:
- Впробувати-блоці (блоці повторних спроб) необхідно розміщувати код, який потенційно може привести до аварійного закриття програми;
- Виняток генерується в блоцікидати. Есликидати спрацює програма почнеться автоматично командвиловити-блоку, ігноруючи решту код в пробувати-блоці;
- вловлює блок – виловити-блок, перехоплює то, що генерує блоккидати. Він обов'язково повинен знаходитися підпробувати-блоком. Нічого не повинно бути прописано між ними;
- виловити-блок не спрацює, якщо виключення не було згенеровано. Програма його просто проігнорує.
Взагалі то, тема винятків в будь-якій мові програмування – досить слизька. Такий механізм вносить як свої переваги, так і свої недоліки і приховані небезпеки використання.
Мова C ++ – proizvodnиy, ніж C, і в цей розвиток включили виключення. наступне розвиток (2008-2009Г.Г.) мови C – це мова Go. З нього виключення були розробниками виключені і з дуже докладною опублікованій аргументацією чому вони це зробили.
Реюме: виключення в C ++ потрібно використовувати, але тільки там, де вони вкрай необхідні, де без них не можна обійтися. В інших випадках краще використовувати традиційний повернення коду помилки.
Допоможіть люди добрі!!! Що неправильно з try у мене?
#include // содержит time()
#include
#include
using namespace std;
int main()
{
setlocale(LC_ALL, "rus");
int s1 = 0;
int s2 = 0;
char exit = 1;
int over = 0;
cout <<
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
cout << " Делите только у нас !!! \n";
cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
do
{
cout << "\n ~~~~~~~~~~ Введите ваши числа: ~~~~~~~~~~ \n";
cout < ";
cin >> s1;
cout < ";
cin >> s2;
try
{
over = s1 / s2;
cout < " << over << endl;
cout << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
cout << " Для продолжения вычислений нажми - 1, Для выхода - 0 \n";
cout << exit;
throw 999;
}
catch (int thr)
{
cout << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
cout << " ~~~~~~~~ Похоже ты допустил ошибку!!! ~~~~~~~~ ";
cout << "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
}
} while (exit != 0);
return 0;
}
А у вас до throw справа не доходить – аварійне завершення настає раніше, при розподілі на 0.
І параметром catch має бути щось, успадковане від класу винятків:
catch( exception const& e ) {
Вітаю. У вас помилка в третьому лістингу.
cout << num1 / num2 << endl; //потрібно вивести за межі оператора if. інакше не працює.
Онлайн компілятор взагалі не компілює код з “пробувати” і т.д. … – показує помилку
1). Потрібно вказувати ЯКИЙ онлайн компілятор – їх багато, і є зовсім з прідурью…
2). У різних стандартах C ++ (наприклад C ++ 11) синтаксис запису блоку try {} виловити – може відрізнятися;
3). Багато онлайн компілятори (кращі) дозволяють вказати той стандарт мови C ++, який буде використовуватися в коді;
Мені більше подобається if-else, тоді спробуйте, бо це не спрацьовує час від часу.
Для тих у кого не працює код вище, використовуйте цей:
#include
using namespace std;
int main()
{
setlocale(LC_ALL, “rus”);
INT num1;
INT піт2;
INT був = 3;
while (var != 0)
{
cout <> num1;
cout <> num2;
cout << "num1 + піт2 = " << num1 + num2 << endl;
cout << "num1 / num2 = ";
пробувати // тут розташовується код, який потенційно може викликати помилку
{
if (піт2 == 0)
{
кидати 999; // генерувати ціле число 999
}
cout << num1 / num2 << endl;
}
виловити (INT Чет)// сюди передасться число, kotoroe sgeneriroval кидок
{
cout << "Ошибка №" << Чет << " – поділ на 0!!!" << endl;
}
cout << "num1 – піт2 = " << num1 – num2 << endl;
cout << "=================================" << endl << endl;
var–;
}
cout << "Программа завершила работу!" << endl << endl;
return 0;
}
77el3m