А если catch-обработчики не содержат инструкции return, с какого места будет продолжено выполнение программы? После завершения обработчика выполнение возобновляется с инструкции, идущей за последним catch-обработчиком в списке. В нашем примере оно продолжается с инструкции return в функции main(). После того как catch-обработчик popOnEmpty выведет сообщение об ошибке, main() вернет 0.
int main() {
iStack stack( 32 );
try {
stack.display();
for ( int x = 1; ix
Говорят, что механизм обработки исключений в C++
не возобновляется с того места, где оно было возбуждено. В нашем
примере управление не возвращается в функцию-член pop(), возбудившую исключение.
11.3.1. Объекты-исключения
Объявлением исключения в catch-обработчике
могут быть объявления типа или объекта. В каких
случаях это следует делать? Тогда, когда необходимо
получить значение или как-то манипулировать объектом,
созданным в выражении throw. Если классы исключений спроектированы
так, что в объектах-исключениях при возбуждении сохраняется
некоторая информация и если в объявлении исключения фигурирует
такой объект, то инструкции внутри catch-обработчика могут
обращаться к информации, сохраненной в объекте выражением throw.
Изменим реализацию класса исключения
pushOnFull, сохранив в объекте-исключении то
значение, которое не удалось поместить в стек.
Catch-обработчик, сообщая об ошибке, теперь будет
выводить его в cerr. Для этого мы сначала модифицируем
определение типа класса pushOnFull следующим образом:
// новый класс исключения:
// он сохраняет значение, которое не удалось поместить в стек
class pushOnFull {
public:
pushOnFull( int i ) : _value( i ) { }
int value { return _value; }
private:
int _value;
};
Новый закрытый член _value содержит число, которое не удалось поместить в стек. Конструктор принимает значение типа int и сохраняет его в члене _data. Вот как вызывается этот конструктор для сохранения значения из выражения throw:
void iStack::push( int value )
{
if ( full() )
// значение, сохраняемое в объекте-исключении
throw pushOnFull( value );
// ...
}
У класса pushOnFull появилась также новая функция-член value(), которую можно использовать в catch-обработчике для вывода хранящегося в объекте-исключении значения:
catch ( pushOnFull eObj ) {
cerr "trying to push value "eObj.value()
"on a full stack\n";
}
Обратите внимание, что в объявлении исключения в catch-обработчике фигурирует объект eObj, с помощью которого вызывается функция-член value() класса pushOnFull.
Объект-исключение всегда создается в точке возбуждения, даже если выражение throw – это не вызов конструктора и, на первый взгляд, не должно создавать объекта.
Например:
enum EHstate { noErr, zeroOp, negativeOp, severeError };
enum EHstate state = noErr;
int mathFunc( int i ) {
if ( i == 0 ) {
state = zeroOp;
throw state; // создан объект-исключение
}
// иначе продолжается обычная обработка
}
В этом примере объект state не используется в качестве объекта-исключения. Вместо этого выражением throw создается объект-исключение типа EHstate, который инициализируется значением глобального объекта state. Как программа может различить их? Для ответа на этот вопрос мы должны присмотреться к объявлению исключения в catch-обработчике более внимательно.