ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4287
Скачиваний: 28
Часть II. Язык программирования С++
166
Для работы механизма обработки исключений в программе
должны быть определены блоки
try
и
catch
, которые организова-
ны следующим образом:
try
{
// тело блока try
}
catch(тип_исключения)
{
// тело блока catch
}
Тело блока
try
содержит код, при исполнении которого может
произойти выброс исключения, а тело блока
catch
содержит код,
который обрабатывает исключение и поэтому также называется
обработчиком исключения
. Отметим, что блок
catch
должен сле-
довать непосредственно за блоком
try
.
Работает механизм обработки исключений следующим образом.
Если внутри блока
try
произошел выброс исключения, посредст-
вом исполнения инструкции с выражением
throw
внутри этого
блока или внутри любой функции, которая вызывается в этом
блоке, то исполнение блока
try
немедленно прекращается неза-
висимо от уровня вложенности, на котором произошел выброс
исключения, а управление передается блоку
catch
. После завер-
шения работы блока
catch
управление передается на первую ин-
струкцию, следующую за этим блоком. При этом блок
catch
обрабатывает только то исключение, тип которого соответст-
вует его
типу_исключения
. Для упрощения терминологии
тип_
исключения
часто также называют
типом обработчика исклю-
чения
.
В листинге 13.1 приведен пример обработки исключения, кото-
рое генерируется при попытке целочисленного деления на ноль.
Листинг 13.1. Обработка исключения
#include <iostream>
using namespace std;
Глава 13. Обработка исключений
167
int divide(int a, int b)
{
if (!b)
throw "Zero divide";
return a / b;
}
int main()
{
int n, m;
try
{
// введите два целых числа через пробел
cout << "Input two integers: ";
cin >> n >> m;
cout << "n/m = " << divide(n,m) << endl;
}
catch(char* str)
{
cout << str << endl; // печатает: Zero divide
}
cout << "OK" << endl;
return 0;
}
Кратко поясним работу этой программы. Пользователь вводит
два целых числа. Если делитель не равен нулю, то программа пе-
чатает частное от деления этих чисел, которое вычисляется
функцией
divide
. Тонкость в том, что функция
divide
проверяет
делитель на равенство нулю. Если он равен нулю, то функция не
вычисляет частное, а выбрасывает исключение "
Zero divide
" ти-
па
char*
. Если исключение выброшено, то как исполнение функ-
ции
divide
, так и исполнение блока
try
немедленно завершается,
а управление передается в блок
catch
. Для этого тип параметра
блока
catch
выбран в соответствии с типом выбрасываемого ис-
ключения.
Часто при обработке исключения нужно знать только тип этого
исключения. В этом случае для типа исключения используют
Часть II. Язык программирования С++
168
пустые структуры. Например, в нашем случае можно было бы
определить исключение типа
struct ZeroDivide{};
Программа обработки такого исключения приведена в листин-
ге 13.2. Заметим, что в этой программе инструкция с выражением
throw
выбрасывает объект типа
ZeroDivide
, а не сам тип. Для это-
го используется конструктор по умолчанию структуры
ZeroDivide
.
Листинг 13.2. Обработка исключения (используя пустой тип)
#include <iostream>
using namespace std;
struct ZeroDivide {};
int divide(int a, int b)
{
if (!b)
throw ZeroDivide();
return a / b;
}
int main()
{
int n, m;
try
{
// введите два целых числа через пробел
cout << "Input two integers: ";
cin >> n >> m;
cout << "n/m = " << divide(n,m) << endl;
}
catch(ZeroDivide)
{
cout << "Zero divide" << endl; // печатает: Zero divide
}
cout << "OK" << endl;
return 0;
}
Глава 13. Обработка исключений
169
В заключение этого раздела скажем, что для выхода из блоков
try
и
catch
можно использовать инструкции передачи управления
return
,
break
,
continue
и
goto
. Невозможно передать управление
внутрь блоков
try
или
catch
, используя инструкцию
goto
.
13.2. Обработка
нескольких исключений
Для обработки исключений разных типов допускается использо-
вание нескольких последовательных блоков
catch
. Если внутри
блока
try
произошел выброс исключения, то управление переда-
ется первому обработчику исключения, тип которого соответст-
вует типу выброшенного исключения. Если такого обработчика
нет, то вызывается функция
terminate
, которая в свою оче-
редь вызывает функцию
abort
, которая и завершает исполнение
программы. Подробно работа этими функциями рассмотрена
в
гл. 36
.
После обработки исключения управление передается на первую
инструкцию, которая следует за последним обработчиком исклю-
чения.
В листинге 13.3 приведена программа, в которой обрабатываются
два типа исключений.
Листинг 13.3. Обработка исключений двух типов
#include <iostream>
using namespace std;
struct ZeroDivide {};
int divide(int a, int b)
{
int r; // остаток от деления
if (!b)
throw ZeroDivide();
r = a % b;
if (r)
throw r;
Часть II. Язык программирования С++
170
return a / b;
}
int main()
{
int n, m;
try
{
// введите два целых числа через пробел
cout << "Input two integers: ";
cin >> n >> m;
cout << "n/m = " << divide(n,m) << endl;
}
catch(ZeroDivide)
{
cout << "Zero divide" << endl; // печатает: Zero divide
}
catch(int &r)
{
cout << "Remainder = " << r << endl; // печатает остаток
}
cout << "OK" << endl;
return 0;
}
13.3. Перехват всех исключений
Для перехвата исключений любого типа используется обработчик
исключения, который имеет следующий вид:
catch(...)
{
// тело блока catch
}
Очевидно, что если такой обработчик исключений используется,
то он должен быть последним в последовательности обработ-
чиков исключений. Иначе он будет перехватывать все исклю-
чения.