Лекция-2.06.ppt
- Количество слайдов: 28
Исключения и обработка исключений 1. Основные понятия об исключениях и их обработке. 2. Генерация (throwing) исключительной ситуации. 3. Отслеживание (catching) исключительной ситуации. 4. Обозначение (claiming) исключительных ситуаций для функции. 5. Повторная генерация исключительной ситуации. 6. Исключительные ситуации с объектами абстрактных типов. 7. Использование наследования с исключительными ситуациями. 8. Иерархия стандартных классов для исключений. Лекция 24. 03. 2014 г. 1
1. Основные понятия об исключениях и их обработке Исключение — это событие, которое не ожидается в «штатном» режиме работы программы, и своим появлением препятствует дальнейшему ее выполнению, например: попытка деления на нуль, обращение к несуществующей базе данных, открытие поврежденного файла, обрыв связи при передаче данных по сети и пр. До появления в языках программирования средств работы с исключениями их обработка выполнялась с использованием стандартных конструкций языка: Ø инструкций выбора if или switch и Ø «кодов завершения» , возвращаемых функциями и анализируемых вызывающими программами. Анализ и обработка исключений были «растворены» в тексте программы. Механизм исключительных ситуаций языка С++ позволяет специальным образом выделить часть программы, в которой возможно появление исключительных ситуаций. Такое отделение обработки исключительных ситуаций от основной программы облегчает ее чтение и сопровождение. Лекция 24. 03. 2014 г. 2
Пример: обработка исключений в клиентской программе (функции main) традиционным способом void inverse(long value, double& answer) { answer = 1. 0/value; } void fraction(long numer, long denom, double& result) { inverse(denom, result); result *= numer; } int main() { long numer, denom; double ans; while (true) { cout << "Введите числитель и положительныйn" << "знаменатель (или любой символ для завершения): "; if ((cin >> numer >> denom) == 0) break; if (denom > 0) { fraction(numer, denom, ans); cout << "Результат: " << ans <<"nn"; } else if (denom == 0) cout << "n. Нулевой знаменатель!nn"; else cout << "n. Отрицательный знаменатель: " << denom <<"nn"; } } Лекция 24. 03. 2014 г. 3
В этом примере оба исключительных состояния (нулевой и отрицательный знаменатель) обнаруживаются в клиентской программе (функции main), а ошибки обрабатываются сразу же по месту их обнаружения. Серверные функции inverse() и fraction() никогда не смогут столкнуться с неверными входными данными и поэтому они выполняются безоговорочно, без проверки допустимости своих входных данных. Устранение ошибок происходит здесь в основной программе с помощью вывода сообщений и повторения запроса на ввод новых входных данных. Основная часть программы (вызов серверной функции fraction()) не отделяется от части программы, обрабатывающей ошибки, но это не вызывает серьезных проблем. Лекция 24. 03. 2014 г. 4
Построить программу подобным образом удается далеко не всегда. Например, бывает так, что ошибку можно обнаружить не сразу, а только после выполнения некоторой обработки в серверной функции, далеко от того места в основной (клиентской) программе, где появилась ошибка. В некоторых случаях такие ошибки могут обрабатываться по месту их обнаружения (т. е. в серверной функции), однако для других ошибок может потребоваться дополнительная информация, отсутствующая в момент их обнаружения в серверной функции. В этом случае информация об ошибке должна возвращаться в клиентскую программу для обработки и, если возможно, для исправления. Все это существенно усложняет программу и делает ее текст практически «нечитабельным» . Лекция 24. 03. 2014 г. 5
Радикальное решение состоит в использовании механизма обработки исключительных ситуаций, что позволяет обойтись без дополнительных параметров функций, возвращаемых функциями значений и сложных соглашений о вызовах. Исключительные ситуации C++ позволяют изменить последовательность передачи управления, когда во время выполнения программы возникает некоторое событие, например ошибка (файл не найден, неверный индекс и т. п. ). Механизм исключительных ситуаций C++ позволяет передать обработку исключительных случаев в другие части исходной программы и упростить основную обработку. За счет этого программа становится удобочитаемой. Обработчики исключительных ситуаций могут размещаться: - в той же функции, которая вызвала исключительную ситуацию, - в вызывающей программе данной функции, - в вызывающей программе вызывающей программы и т. д. Лекция 24. 03. 2014 г. 6
Исключительные ситуации могут быть сгенерированы неявно, операционной системой, как результат недопустимой или неверной операции, или явно в программе специальной инструкцией throw. При генерировании исключительной ситуации может быть создан объект системного класса Exception или любого другого типа (встроенного, определенного программистом, производного от Exception, или независимого от него). Для обработки исключения в код программы включаются один или несколько обработчиков исключений (блоков catch), каждый из которых настроен на свой тип исключения, который указывается в скобках после catch (его еще называют фильтром исключения). Лекция 24. 03. 2014 г. 7
С обработкой исключительных ситуаций связаны три понятия: 1) генерация (throwing) исключительной ситуации, означающая прерывание потока управления и включение механизма обработки исключительных ситуаций; 2) отслеживание (catching) исключительной ситуации обработчиками исключительных ситуаций – блоками кода, «настроенными» на «перехват» определенных исключительных ситуаций; 3) обозначение (claiming) исключительной ситуации для функции: перечисление исключительных ситуаций, которые могут возникнуть в пределах данной функции. Это помогает компилятору (и программистам, разрабатывающим клиентскую часть и осуществляющим сопровождение) узнать, что ожидать от функции и как она должна использоваться. Лекция 24. 03. 2014 г. 8
1. Основные понятия об исключениях и их обработке. 2. Генерация (throwing) исключительной ситуации. 3. Отслеживание (catching) исключительной ситуации. 4. Обозначение (claiming) исключительных ситуаций для функции. 5. Повторная генерация исключительной ситуации. 6. Исключительные ситуации с объектами абстрактных типов. 7. Использование наследования с исключительными ситуациями. 8. Иерархия стандартных классов для исключений. Лекция 24. 03. 2014 г. 9
Если серверная программа обнаружила состояние, дальнейшая последовательность обработки которого ей неизвестна, она может прервать свой поток управления, сгенерировав ( «возбудив» ) исключительную ситуацию, надеясь, что гденибудь (в ее клиенте или клиентах клиента) существует блок кода (обработчик), который умеет обрабатывать подобные ситуации и может принять управление от серверной программы. Синтаксис инструкции генерации исключительной ситуации: throw value; Операнд value данной инструкции может быть объектом любого типа, и предназначен для приёма его обработчиком, настроенным на приём данных именно этого типа. Фактически value является «сигналом» определенной «частоты» , который может принят «антенной» обработчика, настроенной на эту частоту. Лекция 24. 03. 2014 г. 10
Пример. Модифицированная функция inverse(): inline void inverse(long value, double& answer) { answer = (value) ? 1. 0/value : DBL_MAX; if (answer==DBL_MAX) throw MSG: : msg(1); // знаменатель = 0 if (value < 0) throw value; // знаменатель < 0 } class MSG { static char* data []; public: static char* msg(int n) { if (n<1 || n > 4) return data[0]; else return data[n]; } }; char* MSG: : data [] = { "n. Неверный аргумент у msg()n", "n. Нулевой знаменатель недопустимn", "n. Отрицательный знаменатель: ", "n. Введите числитель и положительный знаменатель: ", "n. Значение дроби: " }; Лекция 24. 03. 2014 г. 11
1. Основные понятия об исключениях и их обработке. 2. Генерация (throwing) исключительной ситуации. 3. Отслеживание (catching) исключительной ситуации. 4. Обозначение (claiming) исключительных ситуаций для функции. 5. Повторная генерация исключительной ситуации. 6. Исключительные ситуации с объектами абстрактных типов. 7. Использование наследования с исключительными ситуациями. 8. Иерархия стандартных классов для исключений. Лекция 24. 03. 2014 г. 12
Отслеживание исключительной ситуации – это процесс поиска подходящего обработчика исключительных ситуаций «вверх» по цепочке вызовов функции. Программы, обеспечивающие обработку исключительных ситуаций, реализуются в языке С++ с использованием ключевых слов try и catch. «Опасные» инструкции (в т. ч. и вызовы функций), которые могут сгенерировать исключительные ситуации, помещаются в блоки try, а код обработки исключительных ситуаций включается в блоки catch (эти блоки называются обработчиками). За каждым блоком try должны располагаться один или несколько обработчиков. Каждый обработчик содержит один параметр, тип которого соответствует типу значения, сгенерированного соответствующим исключением. Фактически все обработчики – это перегруженные функции, имеющие уникальные сигнатуры вида: catch(T x), где T – тип Лекция 24. 03. 2014 г. 13 исключения.
Пример: обработка исключений в клиентской программе class MSG {. . . }; char* MSG: : data [] = {. . . }; void inverse(long value, double& answer) {. . . }; void fraction(long numer, long denom, double& result) {. . . }; int main() { long numer, denom; double ans; while (true) { long numer, denom; double ans; cout << MSG: : msg(3); if ((cin >> numer >> denom) == 0) break; try { fraction(numer, denom, ans); cout << MSG: : msg(4) << ans <<"nn"; } catch (char* str) { cout << str; } catch (long val) { cout << MSG: : msg(2) << val << "nn"; } } } Лекция 24. 03. 2014 г. 14
Пример: «Скелет» функции, обеспечивающей обработку исключительных ситуаций void f(){ try {. . . // «опасный» блок кода } catch (Type 1 t 1) {. . . // блок кода обработчика для ситуации типа Type 1 } catch (Type 2 t 2) {. . . // блок кода обработчика для ситуации типа Type 2 }. . . catch (. . . ) { // размещается обязательно последним. . . // блок кода обработчика для ситуации любого типа }. . . // прочие инструкции, следующие за «опасным» блоком кода } Лекция 24. 03. 2014 г. 15
1. Основные понятия об исключениях и их обработке. 2. Генерация (throwing) исключительной ситуации. 3. Отслеживание (catching) исключительной ситуации. 4. Обозначение (claiming) исключительных ситуаций для функции. 5. Повторная генерация исключительной ситуации. 6. Исключительные ситуации с объектами абстрактных типов. 7. Использование наследования с исключительными ситуациями. 8. Иерархия стандартных классов для исключений. Лекция 24. 03. 2014 г. 16
В заголовке (интерфейсе) функции можно задать список исключительных ситуаций, которые могут «проникнуть» за пределы данной функции, и которые должен обрабатывать клиент данной функции: void f() throw (Typel, Туре 2, . . . Type. N) {. . . } Исключительные ситуации могут быть сгенерированы функцией неявно, когда недопустимое условие возникает при вызове функцией своей серверной функции, или явно, с помощью инструкции throw. Если функция не генерирует исключительные ситуации, она может быть объявлена с пустой спецификацией throw(): void f() throw () {. . . } Если функция не содержит спецификации исключительной ситуации, она может сгенерировать любую исключительную ситуацию: void f() {. . . } // возможна любая исключительная ситуация Лекция 24. 03. 2014 г. 17
Обозначение исключительных ситуаций – эффективный метод документирования структуры программы. Когда программист клиентской части желает узнать, какие исключительные ситуации должны обрабатываться клиентской функцией, достаточно изучить интерфейсы всех серверных функций, которые вызываются этой клиентской функцией. Лекция 24. 03. 2014 г. 18
1. Основные понятия об исключениях и их обработке. 2. Генерация (throwing) исключительной ситуации. 3. Отслеживание (catching) исключительной ситуации. 4. Обозначение (claiming) исключительных ситуаций для функции. 5. Повторная генерация исключительной ситуации. 6. Исключительные ситуации с объектами абстрактных типов. 7. Использование наследования с исключительными ситуациями. 8. Иерархия стандартных классов для исключений. Лекция 24. 03. 2014 г. 19
Возможны ситуации, когда обработчик не может полностью обработать перехваченное им исключение и «решает» , что дальнейшую обработку следует «поручить» функции, расположенной выше в цепочке вызовов. Для этого обработчик производит повторную генерацию исключения с помощью инструкции: throw; При повторном возбуждении исключения новый объектисключение не создается. Это имеет значение, если обработчик модифицирует объект, прежде чем возбудить исключение повторно. Лекция 24. 03. 2014 г. 20
1. Основные понятия об исключениях и их обработке. 2. Генерация (throwing) исключительной ситуации. 3. Отслеживание (catching) исключительной ситуации. 4. Обозначение (claiming) исключительных ситуаций для функции. 5. Повторная генерация исключительной ситуации. 6. Исключительные ситуации с объектами абстрактных типов. 7. Использование наследования с исключительными ситуациями. 8. Иерархия стандартных классов для исключений. Лекция 24. 03. 2014 г. 21
Использование простых объектов встроенных типов в качестве объектов исключений существенно ограничивает как количество возможных обработчиков (они все должны различаться типами аргументов!), так и объём информации, передаваемой от места возникновения исключения к месту его обработки. Поэтому часто в качестве объектов исключений используют объекты абстрактных типов данных (классов). Поля таких классов могут нести необходимые данные, а методы позволят обработчику иметь соответствующий доступ к данным объекта исключения. Например, для передачи информации об отрицательном знаменателе можно спроектировать класс Negative. Denom с двумя полями (текст сообщения об ошибке и значение знаменателя) и с методами, осуществляющими доступ к этим полям. Далее приведен пример этого класса. Лекция 24. 03. 2014 г. 22
Пример: класс для исключительной ситуации «отрицательный знаменатель» class Negative. Denom { long val; char* msg; public: Negative. Denom(long value) : val (value), msg (MSG: : msg(2)) { } char* get. Msg( ) const { return msg; } long get. Val() const { return val; } }; Лекция 24. 03. 2014 г. 23
Чтобы сгенерировать объект этого типа, конструктору требуется сообщить значение параметра при помощи метода, который генерирует объект, например inverse(). if (value < 0) // анализ ситуации throw Negative. Denom(value); // генерация исключения В обработчике выполняется обработка этого исключения с использованием методов класса Negative. Denom: catch (const Negative. Denom &nd) { cout << nd. get. Msg() << nd. get. Val() << "nn"; } Лекция 24. 03. 2014 г. 24
1. Основные понятия об исключениях и их обработке. 2. Генерация (throwing) исключительной ситуации. 3. Отслеживание (catching) исключительной ситуации. 4. Обозначение (claiming) исключительных ситуаций для функции. 5. Повторная генерация исключительной ситуации. 6. Исключительные ситуации с объектами абстрактных типов. 7. Использование наследования с исключительными ситуациями. 8. Иерархия стандартных классов для исключений. Лекция 24. 03. 2014 г. 25
Состояния исключений могут быть в определенном смысле «подобными» другу. Это же можно отнести и к данным, которые передаются обработчикам. Поэтому классы исключительных ситуаций часто включают в иерархии наследования. Например, можно доработать классы Zero. Denom и Negative. Denom так, что класс Negative. Denom порождается из класса Zero. Denom: class Zero. Denom { char *msg; public: Zero. Denom(char* message): msg(message){ } void print () const { cout << msg; } }; class Negative. Denom : public Zero. Denom { long val; public: Negative. Denom(char *message, long value): Zero. Denom(message), val(value) { } void print () const { cout << msg << val << "nn"; } }; Лекция 24. 03. 2014 г. 26
1. Основные понятия об исключениях и их обработке. 2. Генерация (throwing) исключительной ситуации. 3. Отслеживание (catching) исключительной ситуации. 4. Обозначение (claiming) исключительных ситуаций для функции. 5. Повторная генерация исключительной ситуации. 6. Исключительные ситуации с объектами абстрактных типов. 7. Использование наследования с исключительными ситуациями. 8. Иерархия стандартных классов для исключений. Лекция 24. 03. 2014 г. 27
Иерархия стандартных классов для исключений exception typeinfo stdexcep new domain_error bad_exception length_error bad_alloc Заголовочные файлы: logic_error out_of_range ios_base: : failure invalid_argument bad_typeid underflow_error bad_cast overflow_error runtime_error range_error ios Лекция 24. 03. 2014 г. 28
Лекция-2.06.ppt