Повторное возбуждение исключения
Может оказаться так, что в одном предложении 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-обработчик вызывает виртуальные функции класса.)