Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
С++ Страуструп.doc
Скачиваний:
4
Добавлен:
18.04.2019
Размер:
2.72 Mб
Скачать

9.1 Обработка ошибок

Создатель библиотеки способен обнаружить динамические ошибки, но не

представляет какой в общем случае должна быть реакция на них.

Пользователь библиотеки способен написать реакцию на такие ошибки,

но не в силах их обнаружить. Если бы он мог, то сам разобрался бы

с ошибками в своей программе, и их не пришлось бы выявлять

в библиотечных функциях. Для решения этой проблемы в язык введено

понятие особой ситуации Ь.

Ь Только недавно комитетом по стандартизации С++ особые ситуации были

включены в стандарт языка, но на время написания этой книги они еще

не вошли в большинство реализаций.

Суть этого понятия в том, что функция, которая обнаружила ошибку и не

может справиться с нею, запускает особую ситуацию, рассчитывая, что

устранить проблему можно в той функции, которая прямо или опосредованно

вызывала первую. Если функция рассчитана на обработку ошибок некоторого

вида, она может указать это явно, как готовность перехватить данную

особую ситуацию.

Рассмотрим в качестве примера как для класса Vector можно

представлять и обрабатывать особые ситуации, вызванные выходом за

границу массива:

class Vector {

int* p;

int sz;

public:

class Range { }; // класс для особой ситуации

int& operator[](int i);

// ...

};

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

особые ситуации, и запускать их можно так:

int& Vector::operator[](int i)

{

if (0<=i && i<sz) return p[i];

throw Range();

}

Если в функции предусмотрена реакция на ошибку недопустимого значения

индекса, то ту часть функции, в которой эти ошибки будут перехватываться,

надо поместить в оператор try. В нем должен быть и обработчик особой

ситуации:

void f(Vector& v)

{

// ...

try {

do_something(v); // содержательная часть, работающая с v

}

catch (Vector::Range) {

// обработчик особой ситуации Vector::Range

// если do_something() завершится неудачно,

// нужно как-то среагировать на это

// сюда мы попадем только в том случае, когда

// вызов do_something() приведет к вызову Vector::operator[]()

// из-за недопустимого значения индекса

}

// ...

}

Обработчиком особой ситуации называется конструкция

catch ( /* ... */ ) {

// ...

}

Ее можно использовать только сразу после блока, начинающегося служебным

словом try, или сразу после другого обработчика особой ситуации. Служебным

является и слово catch. После него идет в скобках описание, которое

используется аналогично описанию формальных параметров функции, а именно,

в нем задается тип объектов, на которые рассчитан обработчик, и,

возможно, имена параметров (см. $$9.3). Если в do_something() или в

любой вызванной из нее функции произойдет ошибка индекса (на любом

объекте Vector), то обработчик перехватит особую ситуацию и будет

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

функций приведут к запуску обработчика в f():

void do_something()

{

// ...

crash(v);

// ...

}

void crash(Vector& v)

{

v[v.size()+10]; // искусственно вызываем ошибку индекса

}

Процесс запуска и перехвата особой ситуации предполагает просмотр

цепочки вызовов от точки запуска особой ситуации до функции, в которой

она перехватывается. При этом восстанавливается состояние стека,

соответствующее функции, перехватившей ошибку, и при проходе по всей

цепочке вызовов для локальных объектов функций из этой цепочки вызываются

деструкторы. Подробно это описано в $$9.4.

Если при просмотре всей цепочки вызовов, начиная с запустившей

особую ситуацию функции, не обнаружится подходящий обработчик, то

программа завершается. Подробно это описано в $$9.7.

Если обработчик перехватил особую ситуацию, то она будет обрабатываться

и другие, рассчитанные на эту ситуацию, обработчики не будут

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

который находится в самой последней вызывавшейся функции, содержащей

соответствующие обработчики. В нашем примере функция f() перехватит

Vector::Range, поэтому эту особую ситуацию нельзя перехватить ни в

какой вызывающей f() функции:

int ff(Vector& v)

{

try {

f(v); // в f() будет перехвачена Vector::Range

}

catch (Vector::Range) { // значит сюда мы никогда не попадем

// ...

}

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]