С++ для начинающих


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


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

throw;

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

catch ( exception eObj ) {

   if ( canHandle( eObj ) )

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

      return;

   else

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

      // catch-обработчик

      throw;

}

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



enum EHstate { noErr, zeroOp, negativeOp, severeError };

void calculate( int op ) {

try {

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

      mathFunc( op );

   }

   catch ( EHstate eObj ) {

      // что-то исправить

      // пытаемся модифицировать объект-исключение

      eObj = severeErr;

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

      // иметь значение severeErr

      throw;

   }

}

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

Чтобы модифицировать исходный объект-исключение, в объявлении исключения внутри catch-обработчика должна фигурировать ссылка:

catch ( EHstate &eObj ) {

   // модифицируем объект-исключение

   eObj = severeErr;

   // повторно возбужденное исключение имеет значение severeErr

   throw;

}

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

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



Содержание раздела