►Механизм исключительных ситуаций...293
Познакомимся поближе с тем, как программа обрабатывает исключительную ситуацию. При возникновении исключения ( throw ) С++ первым делом копирует сгенерированный объект в некоторое нейтральное место. После этого просматривается конец текущего блока try.
Если блок try в данной функции не найден, управление передаётся вызывающей функции, где и осуществляется поиск обработчика. Если и здесь не найден блок try, поиск повторяется далее, вверх по стеку вызывающих функций. Этот процесс называется разворачиванием стека.
Важная особенность разворачивания стека состоит в том, что на каждом его этапе все объекты, которые выходят из области видимости, уничтожаются так же, как если бы функция выполнила команду return. Это оберегает программу от потери ресурсов и "праздно шатающихся" неуничтоженных объектов.
Когда необходимый блок try найден, программа ищет первый блок catch ( который должен находиться сразу за закрывающей скобкой блока try ). Если тип сгенерированного объекта совпадает с типом аргумента, указанным в блоке catch, управление передаётся этому блоку; если же нет, проверяется следующий блок catch. Если в результате подходящий блок не найден, программа продолжает поиск уровнем выше, пока не будет обнаружен необходимый блок catch. Если искомый блок не обнаружен, программа аварийно завершается. Рассмотрим приведённый ниже пример.
/* CascadingException — при компиляции данная программа */
/* может вызвать предупреждения о */
/* том, что переменные f, i и pMsg */
/* не используются */
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
using namespace std ;
class Obj
{
public :
Obj( char c )
{
label = c ;
cout << "Конструирование объекта " << label << endl ;
}
~Obj ( )
{
cout << "Деструкция объекта " << label << endl ;
}
protected :
char label ;
} ;
void f1( ) ;
void f2( ) ;
int f3( )
{
Obj a( 'a' ) ;
try
{
_________________
293 стр. Глава 25. Обработка ошибок и исключения
Obj b( 'b' ) ;
f1( ) ;
}
catch( float f )
{
cout << "Перехват float" << endl ;
}
catch( int i )
{
cout << "Перехват int" << endl ;
}
catch ( ... )
{
cout << string( "Обобщённое исключение" ) << endl ;
}
return 0;
}
int main( int nNumberofArgs , char* pszArgs[ ] )
{
/* печать кириллицы, если Вы не установите программки gccrus.exe и g++rus.exe */
setlocale ( LC_ALL , ".1251" ) ;
f3( ) ;
/* Пауза для того, чтобы посмотреть на результат работы программы */
system( "PAUSE" ) ; return 0 ;
}
void f1( )
{
try
{
Obj c( 'c' ) ;
f2( ) ;
}
catch( string msg )
{
cout << "Перехват строки" << endl ;
}
}
void f2( )
{
Obj d( 'd' ) ;
throw 10 ;
}
В результате работы этой программы на экран будет выведен следующий текст:
Конструирование объекта а
Конструирование объекта b
Конструирование объекта с
Конструирование объекта d
Деструкция объекта d
Деструкция объекта с
Деструкция объекта b
Перехват int
Деструкция объекта а
Press any key to continue...
_________________
294 стр. Часть 5. Полезные особенности
Как видите, прежде чем в функции f2( ) происходит исключение int, конструируются четыре объекта — а, b, с и d. Поскольку в f2( ) блок try не определён, С++ разворачивает стек вызовов функций, что приводит к ликвидации объекта d при разворачивании стека f2( ). В функции f1( ) определён блок try, но его блок catch воспринимает только char*, что не совпадает с брошенным объектом int. Поэтому С++ продолжает просмотр, что приводит к разворачиванию стека функции f1( ) ( при этом ликвидируется объект с ).
В функции f3( ) С++ находит ещё один блок try. Выход из этого блока приводит к выходу из области видимости объекта и b. Первый за блоком try блок catch принимает float, что вновь не совпадает с нашим int, поэтому пропускается и этот блок. Однако следующий блок catch наконец-то воспринимает int, и управление переходит к нему. Последний блок catch, который воспринимает любой объект, пропускается, поскольку необходимый блок catch уже найден и исключение обработано.
Больше книг — больше знаний!
Заберите 20% скидку на все книги Литрес с нашим промокодом
ПОЛУЧИТЬ СКИДКУ