C++.Бархатный путь



Работа системы управления исключением - часть 2


Безымянный объект, созданный в точке возбуждения исключения, инициализирует параметр обработчика исключения. С этой целью нами был определен специальный конструктор копирования. */ { cout << ExcObj.ExcMessage << "... Такое вот сообщение пришло" << endl; /* После завершения выполнения блока обработки исключения, параметр обработчика уничтожается. Для этого мы определили собственную версию деструктора. */ } cout << "За пределами tryБлока: RetMainVal == " << RetMainVal << endl; // cout << ExcMessage << "!!!" << endl; // Обработчик исключений определяет собственную область действия. // ExcMessage оказывается за пределами области действия имени. } cout << "Это конец работы программы." << " И чтобы больше никаких перехватов..." << endl; } int MyFun() throw (int, char *) { int Answer, RetMyFunVal; cout << "MyFun > "; cin >> Answer; cout << Answer << endl; switch (Answer) { case 1: throw 1; cout << "Когда рак на горе свистнет, тогда это сообщение появится."; break; case 2: throw "XXX"; case 3: RetMyFunVal = Fun2(); cout << "Вернулись из Fun2(). RetMyFunVal = " << RetMyFunVal << endl; break; } cout << "Привет из MyFun..." << endl; return Answer; } int Fun2() throw (int) { int Answer; cout << "Fun2 > "; cin >> Answer; cout << Answer << endl; switch (Answer) { case 0: throw 1; /* После возбуждения исключения, процесс нормального выполнения программы прерывается. Мы уже не попадаем в точку возврата функции. Используя стек, минуем функцию MyFun и оказываемся непосредственно в catch-блоке функции main, связанном с исключением типа int. */ default: Answer *= 2; } cout << "Конец работы в Fun2." << endl; return Answer; }

Перед нами программа-полигон для демонстрации взаимодействия генераторов исключений и перехватчиков. Функция main содержит контролируемый блок операторов. Наряду с другими операторами, он составляет тело оператора цикла for.

Функция возвращает значение определённого типа. Тип возвращаемого значения является важной характеристикой функции. Спецификация возвращаемого значения явным образом указывается при объявлении и определении функции. В различных ситуациях та же функция может возбуждать исключения совершенно разных типов и классов. Средством контроля над типами возбуждаемых исключений как раз является спецификация исключений. Этот необязательный элемент в заголовке обеспечивает дополнительный контроль над функцией со стороны транслятора. Хотя функция и может без предварительной спецификации возбуждать любые исключения, им не следует пренебрегать.

Транслятор следит за тем, чтобы не нарушались области действия имён объектов. Областью действия переменной, объявленной непосредственно в try-блоке, является данный try-блок. Соответственно, областью действия переменной, объявленной в одном из catch-блоков, этот самый catch-блок.

try-блок содержит критический код, выполнение которого может привести к возникновению исключительных ситуаций. Возникновение исключительных ситуаций находится под контролем и сопровождается генерацией соответствующего исключения. Одна из точек генерации располагается непосредственно в try-блоке. В данном случае исключительная ситуация возникает, если вызванная перед этим функция в качестве возвращаемого значения возвращает девятку.

Прочие точки генерации исключений, представляющие реакцию на гипотетические исключительные ситуации, располагаются в теле функций, вызываемых из try-блока.

Возникающие в этих функциях исключительные ситуации (по нашему сценарию это реакция на конкретные значения, вводимые в интерактивном режиме) сопровождаются генерацией различных исключений.

В принципе, try-блок может и не содержать участков критического кода и на контролируемом им участке программного кода может и не возникать никаких исключительных ситуаций. В этом случае выполнение этого кода ничем не будет отличаться от выполнения обычного (будто бы бывают обычные блоки) блока операторов. Впрочем, это не наш случай.

И вот, наконец, свершилось! В ходе выполнения контролируемого кода, непосредственно в try-блоке или в теле одной из вызываемых из этого блока функций возникает ситуация, которая может быть квалифицирована как исключительная. Реакцией на неё является возбуждение с помощью throw-оператора соответствующего исключения. С этого момента весь ход выполнения программы меняется.

Немедленно прекращается выполнение любых операторов, располагаемых следом за точкой генерации исключения.

Если точка генерации исключения оказалась в последнем операторе вызываемой функции, то отменяются все мероприятия по предполагаемому возвращению из вызываемой функции.

Тем более отменяется выполнение каких-либо операторов вызова. Точка генерации исключения в определённом смысле оказывается действительно точкой. В этой самой точке принципиально меняется весь дальнейший ход выполнения программы. Сразу после возбуждения исключения начинается поиск соответствующего блока перехвата исключения.

При этом область поиска ограничивается теми блоками операторов (естественно, в том числе и функциями), информация о которых была зафиксирована в стеке на момент возбуждения исключения. Это и понятно, поскольку перехват исключения производится в соответствии с принципом, согласно которому за последствия исключительной ситуации отвечает вызывающая функция. В ходе этого поиска производится действие, подобное "разматыванию" стека. И лишь возможные различия в деталях этих процессов, которые могут зависеть от конкретной реализации, служат аргументом в пользу того, чтобы не делать механизм перехвата исключения заурядным средством управления процессом выполнения.

Существуют чёткие критерии соответствия блока перехвата и возбуждённого исключения. Перечислим их: