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

Спецификация исключения

Синтаксически спецификация исключения является частью объявления и определения функции и имеет следующий вид:

заголовок_функции throw (список_типов)

Здесь список_типов – список типов, которые может иметь выражение throw внутри функции. В объявлении и определении функции спецификация исключения должна записываться одинаково.

Если список пуст, компилятор полагает, что функцией не будет выполняться никакой throw (ни прямо, ни косвенно).

void foo() throw (int, over_flow);

void noex (int i) throw ();

Если спецификация исключения опущена, предполагается, что функцией может быть возбуждено произвольное исключение. Нарушение спецификаций исключений приводит к ошибкам на этапе выполнения. Они отлавливаются функцией unexpected().

terminate() и unexpected()

Предоставляемая системой функция terminate() вызывается, если не было задано ни одного обработчика, «знающего, как обращаться» с исключением. По умолчанию вызывается функция abort(). Она немедленно завершает программу и возвращает управление операционной системе. С помощью set_terminate() может быть задано какое-нибудь другое действие; тем самым задается обработчик. Объявления упомянутых функций находятся в except или except.h.

Предоставляемый системой обработчик unexpected() вызывается, когда функция возбудила исключение, которое отсутствует в ее списке спецификации исключений. По умолчанию вызывается функция terminate(). Или можно воспользоваться set_terminate(), чтобы задать обработчик.

Пример кода с исключениями

В этом разделе мы обсудим некоторые примеры кода с исключениями. Вернемся к перехвату ошибки размера в нашем конструкторе для типа vect, который обсуждался в разделе 7.7, «Перегрузка операторов присваивания и индекса», на стр.203:

В фале vect4.h

vect : : vect (int n) : size (n)

{

if (n < 1) //проверка предусловия

throw (n);

p = new int [n];

if (p = = 0) //проверка постусловия

throw (“СВОБОДНАЯ ПАМЯТЬ ИСЧЕРПАНА”);

}

В фале vect4.cpp

void g (int m)

{

try {

vect a (m);

……

}

catch (int n)

{

cerr << “ОШИБКА РАЗМЕРА” << n << endl;

g(10); //пробуем g допустимого размера

}

catch (const char error)

{

cerr << error << endl;

abort();

}

}

Обработчик заменил недопустимое значение допустимым по умолчанию. Такой подход может быть разумен на этапе отладки системы, когда интегрируется и тестируется множество процедур. Система пытается предоставить дополнительную диагностику. Это аналогично тому, как компилятор пытается продолжать разбор кода после отловленной им синтаксической ошибки. Часто компилятор предоставляет дополнительные сообщения об ошибках, которые оказываются полезными.

Вышеприведенный конструктор проверяет лишь одну переменную на допустимость значений. Этот конструктор выглядит искусственно: вместо того, чтобы непосредственно (прямо в теле конструктора) заменить недопустимое значение допустимым по умолчанию, он запускает исключение и перекладывает заботу об «исправлении» ошибочной переменной на обработчик исключения. Тем не менее именно в приведенной выше форме наиболее очевидно отделено друг от друга то, что является ошибкой, и то, как она должна обрабатываться. Это – ясная методология для разработки отказоустойчивого кода.

В более общем виде конструктор объекта может выглядеть так:

Object : : object (аргументы)

{

if (нештатный_аргумент1)

throw выражение 1;

if (нештатный аргумент2)

throw выражение 2;

……

//попытка создать объект

……

}

Теперь конструктор Object предоставляет набор запускаемых выражений для нештатной ситуации. А блок try может пользоваться информацией для завершения выполнения или исправления некорректного кода.

try {

//……отказоустойчивый код

}

cach (объявление 1) {/исправления для этого случая/}

cach (объявление 2) {/исправления для этого случая/}

…..

cach (объявлениеК) {/исправления для этого случая/}

//теперь все значения допустимы

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

Object_Error {

public:

Object_Error (аргументы); //фиксируем полезную информацию

//члены, содержащие запускаемое выражение исключения

virtual void repair()

{ cerr << “Не удается исправить Object” << endl; abort();

}

};

Object_Error_S1 : public Object_Error {

public:

Object_Error_S1(аргументы);

//дополнительные члены, в которых сосредоточена информация

//о состоянии запускаемого выражения

void repair(); //замещается для обеспечения исправлений

};

…… //другие необходимые производные классы

//для обработки ошибок

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

Стандартные исключения и их использование

Стандартные исключения предоставляются компиляторами С++ и поставщиками библиотек. Например, компилятором Borland запускается исключение типа xalloc, если оператору new не удается выделить место в свободной памяти.

Вот простая программа, позволяющая проверить это.

В файле except.cpp

#include <iostream.h>

#include <except.h> //нужно для xalloc и xmsg

int main()

{

int p, n;

try {

while (true) {

cout << “сколько разместить?“ << endl;

cin >> n;

p = new int [n];

}

}

catch (xalloc x) {cout << “перехвачен xalloc” <<endl;}

catch (…) {cout << “перехват по умолчанию\n” <<endl;}

}

Эта программа выполняется в цикле, пока его не прервет исключение. На нашей системе требование разместить один миллиард целых чисел вызовет обработчик xalloc. А по стандарту ANSI для этих целей служит класс исключений bad_alloc.

Часто использование стандартных исключений состоит в тестировании приведений типов. Стандартное исключение bad_cast объявлено в файле exception. Вот простая программа, использующая RTTI и это исключение:

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