Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Итоговый конспект Тельнов.docx
Скачиваний:
10
Добавлен:
07.04.2023
Размер:
7.75 Mб
Скачать

40. Обработка нештатных ситуаций. Объекты-исключения. Примеры.

Объекты-исключения. Примеры.

В качестве введения в тему рассмотрим два фрагмента кода.

Фрагмент 1

File* f1() { // функция ММ пытается открыть некий файл

File* fp; // возможна нештатная ситуация - ошибка открытия файла

if((fp=fopen(...,...))==NULL) — // возникла ошибка открытия файла

{ cerr << “file open err’; return NULL;} // сообщение и аварийный выход.

return fp; } // успех, нормальный выход

При ошибке открытия файла неплохо бы проанализировать причины неудачи и

предпринять некоторые разумные действия для исправления ситуации.

Фрагмент 2

class X : public Y {......... // нештатная ситуация при создании объекта

X (int size) { // конструктор Х вызывает конструктор У

char *p = new char[size]; // конструктор Х пытается получить память,

if (!p) cerr << “obj create err”; } // неудача! и аварийный return невозможен

…..}; // а конструктор У уже отработал ...

Объект класса Х был создан неудачно, но конструктор объекта-предка успешно

отработал и мог получить (заблокировать) некоторые системные ресурсы.

Вопрос 1: какова дальнейшая судьба этих ресурсов, будут ли они освобождены?

Вопрос 2: как распознавать подобные ситуации и корректно их обрабатывать?

1. Объекты-исключения обеспечивают механизм обработки нештатных ситуаций. В момент возникновения нештатной ситуации с помощью оператор throw создаётся и -выбрасывается- объект-исключение.

2. Оператор Catch перехватывает «выброшенные- объекты-исключения и

обрабатывает нештатные ситуации.

3. Оператор try выделяет группы операторов, для которых устанавливается

контроль за возникновением нештатных ситуаций.

Пример 1

#include <math.h>

#include <iostream>

using namespace std;

class overfiow { // класс объектов-исключений

public: void report() { cerr << "Overflow!" << endl; }

};

unsigned f2 ( float x ) { // при npeo6paaosannn float -> unsigned

if ( fabs(x) >= 65535 ) throw overfiow(); // возможно переполнение

return fabs(x); //переполнение не возникло

}

void main (void) {

try { f2(1.0е10); } // в блоке trу установлен контроль

catch (overflow obj) { obj.report();} // перехватчик объектов-исключений

cout << "Exeption handled” << endl;; // нештатная ситуация обработана

}

Важные замечания по работе с объектами-исключениями

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

2. После отработки оператора throw управление немедленно покидает блок try и начинается поиск подходящего оператора catch среди операторов, которые непосредственно следуют за этим блоком try. В случае успешного перехвата объекта-исключения происходит деструкция всех автоматических объектов, созданных от начала блока try вплоть до отработавшего, оператора throw. Данное явление называется автодеструкцией.

3. Если подходящего перехватчика catch обнаружено не было, объект- исключение перебрасывается «вверх в следующий охватывающий блок try, и поиск продолжается среди операторов catch охватывающего блока try. Программный стек при этом -откручивается= назад, и автодеструкция объектов с автоматическим классом памяти продолжается.

4. Объект-исключение можно явным образом -перебросить- для обработки в охватывающий блок try, просто записав в теле catch оператор throw.

5. Несколько операторов catch могут следовать друг за другом, они будут просматриваться -сверху вниз- в поисках подходящего перехватчика.

6. Если подходящий оператор catch найден и он успешно отработал, тогда управление передается следующему за ним оператору, который не является оператором catch внутрь блока try, откуда был “выброшен” объект- исключение, управление никогда не возвращается. Там уже произошла автодеструкция автоматических объектов.

7. Если ни одного подходящего оператора catch не было найдено, управление попадает в функцию terminate(), которая аварийно завершает приложение.

8. Оператор catch(..) «ловит» любые объекты-исключения.

9. Разрабатывая классы объектов-исключений, следует активно использовать механизмы наследования (примеры см. Страуструп).

Пример 2

int f3 () { …………. //в функции f3 возможно несколько нештатных ситуаций

if (...) throw “error"; // первая нештатная ситуация

if (...) throw overflow(); // вторая нештатная ситуация

……………..}

void main (void ) {

try {………. //в блоке try установлен контроль

int n = f3();; // вызов функции f3

……..}

catch (char* s){ cout << s << endl; } // первый перехватчик

catch (overflow obj) { obj.report(); } // второй перехватчик

cout << “Exceptions handled" << endl; //нештатные ситуации обработаны

}

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

void f4() throw (char*, overflow, exception); означает, что функция f4 может выбрасывать объекты-исключения только трех указанных типов.

Запись throw() означала бы, что функция f4 не может “выбрасывать” никаких объектов исключений. Запись throw(..) означала бы, что функция f4 может «выбрасывать» объекты-исключения любых типов и классов.