ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4286
Скачиваний: 28
Глава 13. Обработка исключений
171
В листинге 13.4 приведена программа, в которой используется
обработчик исключений любого типа.
Листинг 13.4. Использование обработчика исключений
любого типа
#include <iostream>
using namespace std;
struct Zero {};
struct NonZero {};
int main()
{
int n;
try
{
cout << "Input integer: "; // Введите целое число
cin >> n ;
if (n)
throw NonZero();
throw Zero();
}
catch(...)
{
cout << "Zero or NonZero exception" << endl;
}
cout << "OK" << endl;
return 0;
}
13.4. Вложенные исключения
В блок
try
могут быть вложены другие блоки
try
со своими об-
работчиками исключений. В этом случае обработчик исключения
ищется последовательно от самого внутреннего блока
try
к са-
мому внешнему блоку
try
.
Часть II. Язык программирования С++
172
В листинге 13.5 приведен пример программирования вложенных
блоков
try
.
Листинг 13.5. Программирование вложенных блоков
try
#include <iostream>
using namespace std;
struct UnderZero {};
struct Zero {};
struct AboveZero {};
int main()
{
int n;
cout << "Input integer: ";
cin >> n;
try
{
if (n < 0)
throw UnderZero();
try
{
if (n > 0)
throw AboveZero();
throw Zero();
}
catch(AboveZero)
{
cout << "AboveZero exception." << endl;
}
}
catch(UnderZero)
{
cout << "UnderZero exception." << endl;
}
catch(Zero)
{
cout << "Zero exception." << endl;
}
Глава 13. Обработка исключений
173
cout << "OK" << endl;
return 0;
}
Блок
try
с обработчиками исключений может быть вложен в блок
catch
. В этом случае подходящий обработчик исключения ищется
только внутри блока
catch
, в который вложен блок
try
.
Для передачи управления из обработчика исключений другому
обработчику исключений, который находится выше текущего
обработчика исключений в иерархии обработчиков, используется
инструкция с выражением
throw
без объекта. В этом случае новое
исключение не создается, а выбрасывается обрабатываемое ис-
ключение. Этот прием часто используется для освобождения
программой захваченных ранее ресурсов.
В листинге 13.6 приведен пример передачи управления по иерар-
хии обработчиков исключений.
Листинг 13.6. Передача управления по иерархии обработчиков
исключений
#include <iostream>
using namespace std;
struct FreeMemory {};
int main()
{
int* n;
int* m;
try
{
n = new int;
cout << "Input n: "; // введите целое число
cin >> *n ;
try
{
m = new int;
Часть II. Язык программирования С++
174
cout << "Input m: "; // введите целое число
cin >> *m ;
throw FreeMemory(); // нужно освободить память
}
catch(FreeMemory)
{
cout << "m = " << *m << endl;
delete m;
throw; // нужно еще раз освободить память
}
}
catch(FreeMemory)
{
cout << "n = " << *n << endl;
delete n;
}
return 0;
}
Отметим, что использование инструкции
throw
без выражения
в блоке
try
приводит к завершению программы.
13.5. Реализация исключений
Когда функция выбрасывает исключение, то управление переда-
ется обработчику исключений в функцию, которая еще не завер-
шила свою работу. Это происходит потому, что поиск нужного
обработчика исключения происходит по вложенным блокам
try
,
которые могут находиться в разных функциях. В стеке хранятся
адреса возврата и локальные переменные вызванных, но еще не
завершивших свою работу, функций. Механизм обработки ис-
ключений реализован таким образом, что если обработчик вы-
брошенного исключения не найден в текущей функции, то все
локальные объекты, принадлежащие этой функции, уничтожают-
ся, т. е. удаляются из стека, а затем поиск обработчика исключе-
ния продолжается в следующей функции по иерархии вызовов.
Глава 13. Обработка исключений
175
При удалении локальных объектов из стека для каждого из них
вызывается деструктор. Такой процесс поиска нужного обработ-
чика исключения называется
раскруткой стека
(stack unwinding).
Так как механизм обработки исключений работает во время ис-
полнения программы, а не ее компиляции, то он замедляет работу
программы. Поэтому обработкой исключений пользуются только
в исключительных ситуациях для обработки серьезных ошибок в
программе. Как правило, это такие ошибки, обработка которых
невозможна в месте их появления, а решение о дальнейшей рабо-
те программы может приниматься на несколько функциональных
уровней выше, чем блок, в котором произошла ошибка.
В заключение этого раздела отметим, что, для того чтобы умень-
шить издержки на обработку исключения, в обработчике исклю-
чения нужно использовать ссылки.
13.6. Спецификация исключений
Спецификацией исключений
называется перечисление в объявле-
нии функции всех исключений, которые она может выбрасывать.
Спецификации исключений должны совпадать в определении и
во всех объявлениях одной и той же функции. Спецификация ис-
ключений имеет следующий синтаксис:
throw(список_типов)
Здесь
список_типов
включает, через запятую, типы всех исключе-
ний, которые может выбросить функция при своем исполнении.
Например, предполагается, что функция:
void foo(void) throw(char*, int);
может выбросить только исключения типов
char*
и
int
.
Если список типов исключений пуст, то это означает, что функ-
ция не выбрасывает никаких исключений. Например:
void foo(void) throw();
Если же в объявлении функции спецификация исключений от-
сутствует, то это значит, что функция может выбросить исключе-
ние любого типа.