Выбрать главу

обработчика не существует, то управление передается в функцию terminate(),

определенную в стандартной библиотеке C++.

Try-блок может содержать любую инструкцию языка

C++: как выражения, так и объявления. Он вводит локальную

область видимости, так что объявленные внутри него переменные

недоступны вне этого блока, в том числе и в catch-обработчиках.

Например, функцию main() можно переписать так, что объявление переменной

stack окажется в try-блоке. В таком случае обращаться к этой переменной в

catch-обработчиках нельзя:

int main() {

try {

iStack stack( 32 ); // правильно: объявление внутри try-блока

stack.display();

for ( int ix = 1; ix

Можно объявить функцию так, что все ее тело

будет заключено в try-блок. При этом не обязательно

помещать try-блок внутрь определения функции, удобнее

поддерживает наиболее чистое разделение кода для нормальной обработки

и кода для обработки исключений. Например:

int main()

try {

iStack stack( 32 ); // правильно: объявление внутри try-блока

stack.display();

for ( int ix = 1; ix 51; ++ix )

{

// то же, что и раньше

}

return 0;

}

catch ( pushOnFull ) {

// здесь к переменной stack обращаться нельзя

}

catch ( popOnEmpty ) {

// здесь к переменной stack обращаться нельзя

}

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

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

Упражнение 11.3

Напишите программу, которая определяет объект IntArray (тип класса IntArray рассматривался в разделеa 2.3) и выполняет описанные ниже действия.

Пусть есть три файла, содержащие целые числа.

* Прочитать первый файл и поместить в объект IntArray первое, третье, пятое, ..., n-ое значение (где n нечетно). Затем вывести содержимое объекта IntArray.

* Прочитать второй файл и поместить в объект IntArray пятое, десятое, ..., n-ое значение (где n кратно 5). Вывести содержимое объекта.

* Прочитать третий файл и поместить в объект IntArray второе, четвертое, ..., n-ое значение (где n четно). Вывести содержимое объекта.

Воспользуйтесь оператором operator[]() класса IntArray, определенным в упражнении 11.2, для сохранения и получения значений из объекта IntArray. Так как operator[]() может возбуждать исключения, обработайте их, поместив необходимое количество try-блоков и catch-обработчиков. Объясните, почему вы разместили try-блоки именно так, а не иначе.

11.3. Перехват исключений

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

Catch-обработчик состоит из трех частей: ключевого слова catch, объявления одного типа или одного объекта, заключенного в круглые скобки (оно называется объявлением исключения), и составной инструкции. Если для обработки исключения выбрано некоторое catch-предложение, то выполняется эта составная инструкция. Рассмотрим catch-обработчики исключений pushOnFull и popOnEmpty в функции main() более подробно:

catch ( pushOnFull ) {

cerr "trying to push value on a full stack\n";

return errorCode88;

}

catch ( popOnEmpty ) {

cerr "trying to pop a value on an empty stack\n";

return errorCode89;

}

В обоих catch-обработчиках есть объявление типа класса; в первом это pushOnFull, а во втором – popOnEmpty. Для обработки исключения выбирается тот обработчик, для которого типы в объявлении исключения и в возбужденном исключении совпадают. (В главе 19 мы увидим, что типы не обязаны совпадать точно: обработчик для базового класса подходит и для исключений с производными классами.) Например, когда функция-член pop() класса iStack возбуждает исключение popOnEmpty, то управление попадает во второй обработчик. После вывода сообщения об ошибке в cerr, функция main() возвращает код errorCode89.