Скачать презентацию Исключения и обработка исключений примеры программ Лекция 03 Скачать презентацию Исключения и обработка исключений примеры программ Лекция 03

Лекция-2.07.ppt

  • Количество слайдов: 22

Исключения и обработка исключений (примеры программ) Лекция 03. 04. 2014 г. 1 Исключения и обработка исключений (примеры программ) Лекция 03. 04. 2014 г. 1

Демонстрация обработки исключений Программа демонстрирует генерацию (запуск) исключения, его перехват и обработку. Важно уяснить, Демонстрация обработки исключений Программа демонстрирует генерацию (запуск) исключения, его перехват и обработку. Важно уяснить, что при генерации исключения сначала происходит разрушение всех локальных объектов, а уже потом – переход к поиску подходящего обработчика //Программа Ex 005. cpp #include using namespace std; class Some. Class { public: Some. Class() { cout << "start Some. Class()" << endl; } ~Some. Class() { cout << "start ~Some. Class()" << endl; } }; void oz() { Some. Class rb; for(int i = 0; i < 3; i++) cout << "inside a function oz. . . n"; throw 47; } int main() { try { cout << "start main. . . n”; oz(); } catch (int) { cout << "inside catch(int)n”; } Лекция 03. 04. 2014 г. } 2

Демонстрация обработки исключений Программа демонстрирует, как обработчик исключений базового класса перехватывает исключение производного класса Демонстрация обработки исключений Программа демонстрирует, как обработчик исключений базового класса перехватывает исключение производного класса (маскирует его) //Программа Ex 006. cpp #include using namespace std; class X { public: class Trouble {}; class Small : public Trouble {}; class Big : public Trouble {}; void f() { throw Big(); } }; int main() { X x; try { x. f(); } catch(X: : Trouble&) { cout << "caught Trouble" << endl; } catch(X: : Small&) { cout << "caught Small Trouble" << endl; } catch(X: : Big&) { cout << "caught Big Trouble" << endl; } } Лекция 03. 04. 2014 г. 3

Демонстрация обработки исключений В этой программе обработчики размещены в правильном порядке: сначала – обработчики Демонстрация обработки исключений В этой программе обработчики размещены в правильном порядке: сначала – обработчики для производных классов, а за ними – обработчик для базового класса //Программа Ex 006. cpp #include using namespace std; class X { public: class Trouble {}; class Small : public Trouble {}; class Big : public Trouble {}; void f() { throw Big(); } }; int main() { X x; try { x. f(); } catch(X: : Small&) { cout << "caught Small Trouble" << endl; } catch(X: : Big&) { cout << "caught Big Trouble" << endl; } catch(X: : Trouble&) { cout << "caught Trouble" << endl; } } Лекция 03. 04. 2014 г. 4

Демонстрация обработки исключений Еще один пример с иерархией исключений //Программа Ex 004. cpp #include Демонстрация обработки исключений Еще один пример с иерархией исключений //Программа Ex 004. cpp #include #include using namespace std; class Matherr { public: virtual void debug_print() const { cout << "Math_error" << endl; } }; class Int_overflow : public Matherr { const char* op; int a 1, a 2; public: Int_overflow(const char* p, int a, int b) : op(p), a 1(a), a 2(b) {} virtual void debug_print() const { cout << "Int_overflow: " << op << '(' << a 1 << ', ' << a 2 << ')' << endl; } }; int add(int x, int y) { if((x > 0 && y > 0 && x > INT_MAX-y) || (x < 0 && y < 0 && x < INT_MIN-y)) throw Int_overflow("+", x, y); return x+y; } // Продолжение на следующем слайде. . . Лекция 03. 04. 2014 г. 5

Демонстрация обработки исключений void f() { try { int i 1 = add(1, 2); Демонстрация обработки исключений void f() { try { int i 1 = add(1, 2); int i 2 = add(INT_MAX, -2); int i 3 = add(INT_MAX, 2); } catch(Matherr& m) { //catch(Matherr m) { m. debug_print(); } } int main() { f(); return 0; } Лекция 03. 04. 2014 г. 6

Не перехваченные исключения Если ни один из обработчиков, следующих за блоком try, не соответствует Не перехваченные исключения Если ни один из обработчиков, следующих за блоком try, не соответствует типу исключения, то исключение передается в контекст следующего уровня (выше по цепочке вызовов), пока не будет найден подходящий обработчик. Если такой обработчик не находится, автоматически вызывается стандартная библиотечная функция terminate(), которая, в свою очередь, вызывает функцию abort() из стандартной библиотеки С, что приводит к аварийному завершению программы (при этом деструкторы глобальных и статических объектов не вызываются!). Функция terminate() также запускается в том случае, если деструктор локального объекта генерирует исключение в процессе раскрутки стека (во время обработки текущего исключения). !!! Можно заменить стандартную функцию terminate() собственной версией подобной функции при помощи стандартной функции set_terminate() Лекция 03. 04. 2014 г. 7

Не перехваченные исключения //Программа Ex 008. cpp #include <exception> #include <iostream> #include <cstdlib> using Не перехваченные исключения //Программа Ex 008. cpp #include #include #include using namespace std; void My. Terminate() { cout << "inside My. Terminate. . . " << endl; exit(0); } void (*old_terminate)() = set_terminate(My. Terminate); class Bad. Class { public: class A{}; void f() { cout << "inside Bad. Class: : f()" << endl; throw A(); } ~Bad. Class() { cout << "inside ~Bad. Class(). . . " << endl; throw 'c'; } }; int main() { try { Bad. Class b; b. f(); } catch(. . . ) { cout << "inside catch(. . . )" << endl; } } Лекция 03. 04. 2014 г. 8

Зачистка Одно из преимуществ обработки исключений состоит в том, что нормальный ход программы прерывается Зачистка Одно из преимуществ обработки исключений состоит в том, что нормальный ход программы прерывается и управление сразу передается в подходящий обработчик. Одна польза от этого будет , если в момент запуска исключения будет произведена необходимая деинициализация (разрушение объектов, зачистка). Механизм обработки исключений С++ гарантирует, что при выходе из области видимости для всех объектов этой области, конструкторы которых завершены, будут вызваны деструкторы. Следующий пример программы показывает, что для объектов с незавершенными конструкторами деструкторы не вызываются. Лекция 03. 04. 2014 г. 9

Зачистка //Программа Ex 009. cpp #include <iostream> using namespace std; class Trace { static Зачистка //Программа Ex 009. cpp #include using namespace std; class Trace { static int counter; int objid; public: Trace() { objid = counter++; cout << "constructing Trace #" << objid << endl; if(objid == 3) throw objid; } ~Trace() { cout << "destructing Trace #" << objid << endl; } }; int Trace: : counter = 0; int main() { try { Trace n 1; Trace array[5]; // Не все эл. создаются Trace n 2; // Сюда не попадаем } catch(int i) { cout << "caught " << i << endl; } } Лекция 03. 04. 2014 г. 10

Управление ресурсами Одно из преимуществ обработки исключений состоит в том, что нормальный ход программы Управление ресурсами Одно из преимуществ обработки исключений состоит в том, что нормальный ход программы прерывается и управление сразу передается в подходящий обработчик. Однако польза от этого будет , если в момент запуска исключения будет произведена необходимая деинициализация (разрушение объектов, зачистка). Механизм обработки исключений С++ гарантирует, что при выходе из области видимости для всех объектов этой области, конструкторы которых завершены, будут вызваны деструкторы. Следующий пример программы показывает, что для объектов с незавершенными конструкторами деструкторы не вызываются. Лекция 03. 04. 2014 г. 11

Управление ресурсами //Программа Ex 010. cpp Зависшие указатели #include <iostream> #include <cstddef> using namespace Управление ресурсами //Программа Ex 010. cpp Зависшие указатели #include #include using namespace std; class Cat { public: Cat() { cout << "Cat()" << endl; } ~Cat() { cout << "~Cat()" << endl; } }; class Dog { public: void* operator new(size_t sz) { cout << "allocating a Dog" << endl; throw 47; // Имитация нехватки памяти } void operator delete(void* p) { cout << "deallocating a Dog" << endl; : : operator delete(p); } }; class Use. Resources { Cat* bp; Dog* op; public: Use. Resources(int count = 1) { cout << "Use. Resources()" << endl; bp = new Cat[count]; op = new Dog; } ~Use. Resources() { cout << "~Use. Resources()" << endl; delete [] bp; // Уничтожение массива delete op; } }; int main() { try { Use. Resources ur(3); } catch(int) { cout << "inside handler" << endl; } } // В результате имеем 4 зависших указателя! Лекция 03. 04. 2014 г. 12

Управление ресурсами на уровне объектов Чтобы предотвратить утечку ресурсов, как это было в предыдущей Управление ресурсами на уровне объектов Чтобы предотвратить утечку ресурсов, как это было в предыдущей программе, необходимо отказаться от «низкоуровневого» выделения ресурсов одним из следующих способов: - перехват исключений внутри конструктора с последующим освобождением ресурса; - выделение ресурсов только в конструкторе объекта, чтобы освобождение ресурсов могло выполняться внутри деструктора. Во втором варианте каждая операция выделения ресурсов становится «атомарной» (является частью жизненного цикла локального объекта). Если выделение ресурса завершается неудачей, другие объекты будут корректно уничтожены в процессе раскрутки стека. Эта методика называется получением ресурсов при инициализации. В следующей программе эта задача решается с помощью шаблона – «обертки» для указателей. Конструкторы объектов, созданных на основе данного шаблона, вызываются до основного кода конструктора Use. Resurces, и для любого конструктора, завершившегося до возникновения исключения, в процессе раскрутки стека будет вызван соответствующий деструктор. Лекция 03. 04. 2014 г. 13

Управление ресурсами на уровне объектов //Программа Ex 011. cpp Безопасные, атомарные указатели #include <iostream> Управление ресурсами на уровне объектов //Программа Ex 011. cpp Безопасные, атомарные указатели #include #include using namespace std; template class PWrap {// Шаблон – «обертка» для указателей T* ptr; public: class Range. Error {}; // класс исключения PWrap() { ptr = new T[sz]; cout << "PWrap constructor completed" << endl; } ~PWrap() { delete [] ptr; cout << "PWrap destructor completed" << endl; } T& operator[](int i) throw(Range. Error) { if(i >= 0 && i < sz) return ptr[i]; throw Range. Error(); } }; // Продолжение на следующем слайде. . . Лекция 03. 04. 2014 г. 14

Управление ресурсами на уровне объектов // Начало на предудущем слайде … class Cat { Управление ресурсами на уровне объектов // Начало на предудущем слайде … class Cat { public: Cat() { cout << "Cat()" << endl; } ~Cat() { cout << "~Cat()" << endl; } }; class Dog { public: void* operator new[](size_t) { // Имитация нехватки памяти cout << "Allocating a Dog" << endl; throw 47; } void operator delete[](void* p) { cout << "Deallocating a Dog" << endl; : : operator delete[](p); } }; // Продолжение на следующем слайде … Лекция 03. 04. 2014 г. 15

Управление ресурсами на уровне объектов class Use. Resources { PWrap<Cat, 3> cats; // Создаем Управление ресурсами на уровне объектов class Use. Resources { PWrap cats; // Создаем 3 «кота» PWrap dog; // Создаем одну «собаку» , и при вызове перегруженной операции // new получаем исключение. . . public: Use. Resources() { cout << "Use. Resources()" << endl; } ~Use. Resources() { cout << "~Use. Resources()" << endl; } }; int main() { try { Use. Resources ur; } catch(int) { cout << "inside handler" << endl; } catch(. . . ) { cout << "inside catch(. . . )" << endl; } } Лекция 03. 04. 2014 г. 16

Блоки try уровня функций Исключения при выполнении конструкторов происходят достаточно часто. Пусть, например, мы Блоки try уровня функций Исключения при выполнении конструкторов происходят достаточно часто. Пусть, например, мы хотим обработать исключения, происходящие при инициализации вложенных объектов или подобъектов базовых классов. Для этого инициализация таких подобъектов заключается в блоки try уровня функций. В отличие от обычного синтаксиса, блоком try для инициализаторов конструкторов является само тело конструктора (см. пример на след. слайде). Лекция 03. 04. 2014 г. 17

Блоки try уровня функций // Обработка исключений в подобъектах #include <iostream> using namespace std; Блоки try уровня функций // Обработка исключений в подобъектах #include using namespace std; class Base { int i; public: class Base. Except {}; Base(int i) : i(i) { throw Base. Except(); } }; class Derived : public Base { public: class Derived. Except { const char* msg; public: Derived. Except(const char* msg) : msg(msg) {} const char* what() const { return msg; } }; Derived(int j) try : Base(j) { cout << "This won't print" << endl; } catch (Base. Except&) { throw Derived. Except("Base subobject threw"); ; } }; int main() { try { Derived d(3); } catch (Derived: : Derived. Except& d) { cout << d. what() << endl; } } Лекция 03. 04. 2014 г. 18

Блоки try уровня функций Следующий пример показывает, что допускается создание блоков try уровня функции Блоки try уровня функций Следующий пример показывает, что допускается создание блоков try уровня функции для любых функций, в том числе и для main: // Блоки try уровня функций #include using namespace std; int main() try { cout << "start main. . . " << endl; throw "exception main"; } catch(const char* msg) { cout << msg << endl; return 1; } Лекция 03. 04. 2014 г. 19

Стандартные исключения Исключения стандартной библиотеки могут использоваться в пользовательских программах. Как правило, проще и Стандартные исключения Исключения стандартной библиотеки могут использоваться в пользовательских программах. Как правило, проще и удобнее начать со стандартного класса исключения, чем пытаться определять собственный класс. Даже если стандартный класс делает не совсем то, что нужно, на его основе всегда можно создать производный класс. Все стандартные классы исключений в конечном счете являются производными от класса exception (см. след. слайд). Его основными подклассами являются logic_error и runtime_error, которые имеют конструкторы со строковыми аргументами. Это позволяет сохранить сообщение в объекте исключения и извлечь его позднее с помощью функции exception: : what(). Лекция 03. 04. 2014 г. 20

Иерархия стандартных классов для исключений exception typeinfo stdexcep new domain_error bad_exception length_error bad_alloc Заголовочные Иерархия стандартных классов для исключений 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 Лекция 03. 04. 2014 г. 21

Стандартные исключения // Создание класса исключения, производного от std: : runtime_error #include <stdexcept> #include Стандартные исключения // Создание класса исключения, производного от std: : runtime_error #include #include using namespace std; class My. Error : public runtime_error { public: My. Error(const string& msg = "") : runtime_error(msg) {} }; int main() { try { throw My. Error("my message"); } catch (My. Error& x) { cout << x. what() << endl; } } Лекция 03. 04. 2014 г. 22