Когда в некоторой области действия исключение выброшено, но не перехвачено, стек функциональных вызовов начинает разматываться и делается попытка перехватить исключение в следующем, внешнем блоке try...catch.
Разматывание стека вызовов означает, что функция, в которой исключение не
перехвачено, завершается, все ее локальные переменные уничтожаются
и управление возвращается оператору, ранее вызвавшему эту функцию. Если
этот оператор охвачен try-блоком, делается попытка перехватить исключение.
Если оператор не охвачен try-блоком, снова происходит разматывание стека.
Если никакой catch-обработчик так и не перехватывает исключение,
вызывается функция terminate для завершения программы. Программа на рис. 16.4
демонстрирует разматывание стека.
// Рис. 16.4: TEST4.cpp
// Демонстрация разматывания стека.
#include <iostream>
using std::cout;
using std::endl;
#include <stdexcept>
using std::runtime_error;
// function3 выбрасывает ошибку времени выполнения
void function3() throw (runtime_error)
{
cout << "In function 3" << endl;
// нет try-блока, стек разматывается, возврат в function2
|
|
throw runtime_error("runtime_error in function3");
} // конец function3
// function2 вызывает function3
void function2() throw (runtime_error)
{
cout << "function3 is called inside function2" << endl;
function3(); // стек разматывается, возврат в functionl
} // конец function2
// functionl вызывает function2
void functionl() throw (runtime_error)
{
cout << "function2 is called inside functionl" << endl;
function2(); // стек разматывается, возврат в main
} // конец functionl
// демонстрация разматывания стека
int main()
{
// вызвать functionl
try
{
cout << "functionl is called inside main" << endl;
functionl(); // вызвать functionl, выбрасывающую runtime_error Управление исключениями
} // конец try
catch (runtime_error &error) // обработать runtime_error
{
cout << "Exception occurred: " << error.what() << endl;
cout << "Exception handled in main" << endl;
} // конец catch
return 0;
} // конец main
/*
functionl is called inside main
function2 is called inside functionl
function3 is called inside function2
In function 3
Exception occurred: runtime_error in function3
Exception handled in main
*/
Блок try в main (строки 37-41) вызывает functionl (строки 27-31). Затем
functionl вызывает function2 (строки 20-24), которая в свою очередь
вызывает function3 (строки 11-17). Строка 16 функции function3 выбрасывает
объект runtime__error. Однако поскольку оператор throw в строке 16 не охвачен
никаким try-блоком, происходит разматывание стека: выполнение function3
завершается в строке 16, и управление возвращается оператору в function2,
который вызвал function3 (т.е. строке 23). Поскольку строка 23 не охвачена
никаким try-блоком, снова происходит разматывание стека — function2
завершается в строке 23 и возвращает управление оператору в functionl,
который вызвал function2 (т.е. строке 30). Строка 30 также не охвачена
try-блоком, и стек разматывается еще раз — functionl завершается в строке 30 и
|
|
возвращает управление оператору в main, вызвавшему functionl (т.е. строке 40).
Этот оператор охвачен try-блоком в строках 37-41, поэтому первый
подходящий catch-обработчик после этого try-блока (строки 42-46) перехватывает
и обрабатывает данное исключение. В строке 44 используется функция what,
чтобы вывести сообщение об ошибке. Как вы помните, это виртуальная
функция класса exception, которую можно переопределить в производном классе,
чтобы выводилось соответствующее сообщение.