Программирование >>  Инициализация объектов класса, структура 

1 ... 174 175 176 [ 177 ] 178 179 180 ... 395


void calculate( int op ) { try {

mathFunc( op );

catch ( EHstate eCbj ) {

/ / eCbj - копия сгенерированного объекта-искчения

созданного выражением throw.

Объявление исключения в этом примере напоминает передачу параметра по значению. Объект eCbj инициализируется значением объекта-исключения точно так же, как переданный по значению формальный параметр функции - значением соответствующего фактического аргумента. (Передача параметров по значению рассматривалась в разделе 7.3.)

Как и в случае параметров функции, в объявлении исключения может фигурировать ссылка. Тогда catch-обработчик будет напрямую ссылаться на объект-исключение,

void calculate( int op ) {

try {

mathFunc( op );

catch ( EHstate &eCbj ) {

/ / eCbj сс1лается на сгенерированн объект-искчение

сгенерированный выражением throw, а не создавать его локальную копию:

Для предотвращения ненужного копирования больших объектов применять ссылки следует не только в объявлениях параметров типа класса, но и в объявлениях исключений того же типа.

В последнем случае catch-обработчик сможет модифицировать объект-исключение. Однако переменные, определенные в выражении throw, остаются без изменения. Например, модификация eCbj внутри catch-обработчика не затрагивает глобальную

void calculate( int op ) {

try {

mathFunc( op );

catch ( EHstate &eCbj ошибку

eCbj = noErr; глобальная переменная state не изменилась

/ / исправить ошибку, вызвавшую искчение ; глобальная переменная st

переменную state, установленную в выражении throw:

calculate() вызывает определенную выше miathFunc (). При входе в catch-обработчик внутри calculate() объект eCbj инициализируется копией объекта-исключения,



Catch-обработчик переустанавливает eCbj в noErr после исправления ошибки, вызвавшей исключение. Поскольку eCbj - это ссылка, можно ожидать, что присваивание модифицирует глобальную переменную state. Однако изменяется лишь объект-исключение, созданный в выражении throw, поэтому модификация eCbj не затрагивает state.

11.3.2. Раскрутка стека

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

В нашем примере первая функция, для которой нужен catch-обработчик, - это функция-член pop() класса iStack. Поскольку выражение throw внутри pop() не находится в try-блоке, то программа покидает pop() , не обработав исключение. Следующей рассматривается функция, вызвавшая pop() , то есть main() . Вызов pop() внутри miain() находится в try-блоке, и далее исследуется, может ли хотя бы одно ассоциированное с ним предложение catch обработать исключение. Поскольку обработчик исключения popCnEmpty имеется, то управление попадает в него.

Процесс, в результате которого программа последовательно покидает составные инструкции и определения функций в поисках предложения catch, способного обработать возникшее исключение, называется раскруткой стека. По мере раскрутки прекращают существование локальные объекты, объявленные в составных инструкциях и определениях функций, из которых произошел выход. C++ гарантирует, что во время описанного процесса вызываются деструкторы локальных объектов классов, хотя они исчезают из-за возбужденного исключения. (Подробнее мы поговорим об этом в главе

19.)

Если в программе нет предложения catch, способного обработать исключение, оно остается необработанным. Но исключение - это настолько серьезная ошибка, что программа не может продолжать выполнение. Поэтому, если обработчик не найден, вызывается функция terminate() из стандартной библиотеки C++. По умолчанию terminate() активизирует функцию abort() , которая аномально завершает программу. (В большинстве ситуаций вызов abort() оказывается вполне приемлемым решением. Однако иногда необходимо переопределить действия, выполняемые функцией terminate(). Как это сделать, рассказывается в книге [STROUSTRUP97].)

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



catch ( exception eCbj ) {

if ( canHandle( eCbj ) )

обработать исключение return;

else

повторно возбудить исключение, чтобы его перехватил другой catch-обработчик throw;

внутри составной инструкции, являющейся частью catch-обработчика:

При повторном возбуждении новый объект-исключение не создается. Это имеет значение, если catch-обработчик модифицирует объект, прежде чем возбудить исключение

enum EHstate { noErr, zeroCp, negativeCp, severeError }; void calculate( int op ) {

try {

исключение, возбужденное mathFunc(), имеет значение zeroCp mathFunc( op );

catch ( EHstate eCbj ) { что-то исправить

/ / пахтаемся модифицировать объект-искчение eCbj = severeErr;

предполагалось, что повторно возбужденное исключение будет иметь значение severeErr throw;

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

функции компилятору в точке активизации уже известно, какая из перегруженных функций будет вызвана. При обработке же исключения компилятор не знает, в какой функции находится catch-обработчик и откуда возобновится выполнение программ:. Функция terminate() предоставляет механизм времени выполнения, который извещает пользователя о том, что подходящего обработчика не нашлось.

11.3.3. Повторное возбуждение исключения

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

throw;

которая вновь генерирует объект-исключение. Повторное возбуждение возможно только



1 ... 174 175 176 [ 177 ] 178 179 180 ... 395

© 2006 - 2025 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика