Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции / LECS18.DOC
Скачиваний:
42
Добавлен:
16.04.2013
Размер:
92.67 Кб
Скачать

Запуск исключений

Синтаксически выражение throw может принимать следующие две формы:

throw выражение

throw

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

Запущенное с помощью throw выражение – это временный статический объект, существующий до тех пор, пока не будет произведен выход из обработчика исключения. Выражение отлавливается обработчиком, который может использовать его значение:

В файле throw1.Cpp

#include <iostream.h>

void foo()

{

int i;

//покажем как запускается исключение

i = -15;

throw i;

}

int main ()

{

try {

foo();

}

catch (int n)

{ cerr <<”Перехваченное выражение\n” << n <<endl; }

}

Целое значение, запущенное throw I, существует, пока существует обработчик catch (int n) с целой сигнатурой. Это выражение доступно для использования внутри обработчика в качестве его аргумента.

Когда вложенная функция запускает исключение, стек процессов раскручивается, пока не будет найден обработчик исключений. Соответственно, выход из каждого завершенного локального процесса вызывает уничтожение автоматических объектов:

В файле throw1.cpp

void foo()

{

int I, j;

…..

throw I;

…...

}

void call_foo()

{

int k;

…..

foo();

…...

}

int main()

{

try{

call_foo(); //при выходе из foo уничтожаются i и j

}

catch (int n) {…..}

}

Перезапуск исключений

Использование throw без выражения перезапускает перехваченное исключение. Тот catch, который перезапускает исключение, не может заканчивать обработку существующего исключения. Он передает управление в ближайший окружающий блок try, где вызывается обработчик, способный отловить все еще существующее исключение. Выражение исключения существует, пока не завершено выполнение всех обработчиков. Выполнение продолжается после самого внешнего блока try, который последним обработал перезапущенное выражение.

Вот пример перезапуска исключения:

catch (int n)

{

…..

throw ; //перезапуск

}

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

Выражения исключений

По замыслу, запущенное исключение «передает» информацию обработчикам. Часто обработчики не нуждаются в этой информации. Например, обработчику, выводящему сообщение и прерывающему выполнение программы, не нужна информация из его окружения. Однако пользователь может пожелать, чтобы выводилась дополнительная информация, которую можно было бы использовать как подспорье в выборе надлежащих действий. В таком случае следует упаковать нужную информацию в объект:

class vect_error {

private:

//тип ошибки: границы, нет памяти, другое

enum error { bounds, heap, other } e_type;

//верхняя граница, индекс, размер

int ub, index, size;

public:

vect_error(error, int, int);

vect_error(error, int);

……

};

Теперь запуск выражения с помощью типа vect_error будет более информативен для обработчика, чем запуск выражений простых типов:

……

throw vect_error (bounds, I, ub);

…….

Пробные блоки try

Синтаксически блок try выглядит так:

try

составная_инструкия

список_обработчиков

Блок try является контекстом для определения того, какие обработчики вызываются при возбуждении исключения. Порядок, в котором определены обработчики, задает порядок, в котором будут пробоваться обработчики подходящего типа для возбужденного исключения:

try{

……

throw (“SOS”);

……

io_condition eof (argv[i]);

throw (eof);

……

}

catch (const char) {…..}

catch (io_condition& x) {…..}

Выражение throw соответствует типу обработчика catch, если оно:

1.точно совпадает с типом catch;

2.является производным типом открытого базового класса типа обработчика;

3.является типом возбуждаемого объекта, который может быть преобразован к типу указателя, являющегося аргументом catch.

Ошибочно приводить список обработчиков в порядке, исключающем возможность вызова некоторых из них. Например:

catch (void) //будет соответствовать любому char

catch (char)

catch (BaseTypeError&) //Вызывается даже при DerivedTypeError

catch (DerivedTypeError&)

//предполагается, что класс DerivedTypeError

//является производным от BaseTypeError

Блоки try могут быть вложенными. Если нет ни одного подходящего обработчика непосредственно в данном блоке try, то обработчик будет выбран из ближайшего охватывающего блока try. Если невозможно подобрать надлежащий обработчик, используется поведение по умолчанию, которым является terminate() (см.раздел 11.8, «terminate() и unexpected()», на стр.321).

Обработчики

Синтаксически обработчик имеет вид:

catch (формальный_аргумент)

составная_инструкция

Обработчик catch выглядит как объявление функции одного аргумента без возвращаемого типа.

В файле catch.cpp

catch (charmessage)

{

cerr << message << endl;

exit(1);

}

catch (…) //будет выполнено действие по умолчанию

{

cerr << “ВОТ И ВСЕ!” << endl;

abort();

}

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

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

Соседние файлы в папке Лекции