#7 Исключения.pptx
- Количество слайдов: 24
Исключения Степанюк Константин Сергеевич 24 const@gmail. com
Задание • Описать класс Person, имеющий поля first. Name и last. Name • Описать производный класс Student расширяющий класс Person, имеющий поле group. Num • Для каждого поля описать (прототипы) функции селекторы и модификаторы • Описать и реализовать виртуальную функцию print(), которая выводит список всех полей класса на экран
class Devided. By. Zero. Exception { public: Devided. By. Zero. Exception() : message("Деление на нуль") {} void print. Message() const {cout <
Перехват исключений • Исключения, находящиеся внизу иерархии наследования должны перехватываться первыми voidf() { try { //… } catch (overflow_error) { //… } catch (runtime_error) { //… } catch (bad_alloc){ //… } catch (exception){ //… } catch (…) { … } }
Исключения стандартной библиотеки
Обработка исключений для перехвата исключения с возможностью работы с ним, необходимо в блоке catch использовать переменную –формальный параметр: try { … } catch (exception &ex) { cout<
Исключения и параметры функций • Синтаксис определения блоков catch во многом похож на синтаксис объявления функций: class Widget {…}; class My. Ex: public excetpion {…}; void f(Widget w); void g(Widget &w); void h(const Widget &w); void bar(Widget *pw); void foo(const Widget *pw); catch(My. Ex ex); catch(My. Ex &ex); catch(const My. Ex &ex); catch(My. Ex *pe); catch(const My. Ex *pe); • Главное отличие: при генерации исключения всегда происходит копирование выбрасываемого объекта, а в случае вызова функции по ссылке –копирования не происходит
Исключения и функции -пример: class Parent {…}; class Child: public Parent{…}; void f (Parent &w); … void g () { Child ch; Parent &rp = ch; //rp ссылаетсяна объект класса Child f(rp); //В функцию f передан объект класса Child try { //вызывается конструктор. Parent(const Parent&) throw rp; //выброшен объект класса Parent!!! } catch (Parent &pe) { //перехвачен объект класса Parent } }
Перехват исключений по значению и через указатель • перехват по значению –лишнее копирование: try { throw My. Ex(); //копирование при выбросе } catch (My. Ex ex) {} //копирование при перехвате • перехват через указатель –кто освободит память? f () { throw new My. Ex(); } g () { try { f(); } catch (My. Ex *pe) { //нужно не забыть освободить память delete pe; //а в друг объект не был создан в свободной //памяти? } }
Лучшая стратегия –перехват по ссылке • При перехвате по ссылке не происходит лишнего копирования объекта исключения и при этом сохраняются преимущества полиморфизма: class Base. Exception {…}; class Child. Exception : public Base. Exception{…}; f() { //… throw Child. Exception(); } g() { try { } catch (Base. Exception&ex) { //перехвачен объект класса Child. Exception } }
Исключения и функции –итог • В отличие от функций при возбуждении исключения всегда происходит копирование выбрасываемого объекта • В отличие от функций, где для приведения типов аргументов разрешены преобразования определяемые пользователем, при перехвате исключений рассматриваются только преобразования вверх по иерархии наследования (upcast) • Блоки catch срабатывают в порядке их перечисления (указания), а не по принципам наилучшего соответствия типа аргумента, как это имеет место быть при разрешении перегруженных функций
Проблема управления ресурсами void use. File(const char* fname) { FILE *fp = fopen(fname, “w”); … // вдруг произойдет исключение? fclose(fp); } void use. File 2(const char* fname) { FILE *fp = fopen(fname, ”w”); try { //… } catch (…) { fclose(fp); //некрасиво –две точки закрытия throw; } fclose(fp); // легко можно запутаться }
Для ресурсов можно использовать классы –обертки class File. Ptr { FILE *fp; public: File. Ptr(const char* path, const char* mode); File. Ptr(FILE *fp) { this->fp = fp; } ~File. Ptr() { fclose (fp); } operator FILE*() {return fp; } }; void use. File 3 (const char *fname) { File. Ptr fp(fname, ”w”); //… Даже если возникнет исключение объект будет удален, // вызовется деструктор ~File. Ptr в котором закроется файл } • Удаление объектов происходит в процессе обратной раскрутки стека при обработки исключений (“stack unwinding”)
Исключения при создании объектов • Объект не считается созданным пока не завершилось создание всех его частей и не завершил свою работу конструктор • В случае возникновения исключительной ситуации во время создания объекта, все уже созданные части корректно уничтожаются в процессе обратной раскрутки стека • Следует избегать выброса исключений из деструктора, так как в случае если деструктор выполняется в процессе обратной раскрутки стека при обработки исключения и выброшено новое исключение, то вызывается функция std: : terminate
Функция terminate() • Вызывается при разрушении стека: – если выбрасывается исключение во время обратной раскрутки стека при уже выброшенном исключении – если вызывается throw; вне блока перехвата исключения (повторная генерация если выброса исключения не было) – если произошло исключение но не было перехвачено – если конструктор глобального статического объекта завершается аварийно с выбросом исключения • По умолчанию terminate() вызывает abort() • set_terminate позволяет установить обработчик terminate • bool uncaught_exception() проверяет было ли исключение перехвачено (можно ли вызвать throw)
Декларация списка исключений void f() throw (Exception 1, Exception 2) {} • Используется для спецификации списка допустимых к генерации исключений в функции • Если функция попытается выбросить исключение не являющееся объектом типа Exception 1 или Exception 2 или их наследников, то произойдет вызов функции ловушки std: : unexpected(), которая по умолчанию вызывает std: : terminate(), но может быть переопределена программистом (set_unexpected) • Проверка осуществляется на этапе исполнения а не компиляции, проверка на этапе компиляции отдана на усмотрение разработчикам сред void f() { // Может выбрасывать любые исключения } void f() throw () { //Не может выбрасывать исключения }
Исключение bad_exception • Менее радикальный механизм чем вызов terminate в обработчике unexpected • Будучи добавленным в список специфицируемых функцией исключений обеспечивает выброс исключения bad_exception вместо вызова функции-ловушки unexpected class X {}; class Y {}; void f() throw (X, std: : bad_exception) { //… throw Y(); //Выбросится std: : bad_exception вместо вызова //unexpected }
Исключения и конструкторы class Image { public: Image(const string& file. Name)}; class Audio. Clip { public: Audio. Clip(const string& file. Name) }; class Entry { string the. Name; Image *p. Image; Audio. Clip *p. Clip; public: Entry(const string& name, const string& image. Location, const string& audio. Location) : the. Name(name), p. Image(0), p. Clip(0) { p. Image = new Image(image. Location); p. Clip = new Audio. Clip(audio. Location); } ~Entry() { delete p. Image; delete p. Clip; } };
Обработка исключений в конструкторе Entry: : Entry(const string& name, const string& image. Location, const string& audio. Location) : the. Name(name), p. Image(0), p. Clip(0) { try { p. Image = new Image(image. Location); p. Clip = new Audio. Clip(audio. Location); } catch (…) { delete p. Image; delete p. Cilp; throw; } }
Обработка исключений в блоке инициализации Entry: : Entry(const string& name, const string& image. Location, const string& audio. Location) try : the. Name(name), p. Image(new Image(image. Location)), p. Clip(new Audio. Clip(audio. Location)) { //Тело конструктора, также находящееся //в области действия //try -catch } catch (…) { delete p. Image; delete p. Clip; //… }
Использование auto_ptr class Entry { string the. Name; auto_ptr
placement delete void* operator new (size_t, void*) throw(); void* operator new[] (size_t, void*) throw(); void operator delete(void *p, void*) throw(); void operator delete[](void *p, void*) throw(); • placement delete вызывается если произошло исключение при вызове соответствующего placement new
Проверка на внимательность class Parent. Exception {}; class Child. Exception : public Parent. Exception {}; int main() { try { throw Child. Exception(); } catch(Parent. Exception) { cout <<"Parent. Exception" <
Упражнение • Создать класс Rectangle(прямоугольник). Класс имеет атрибуты length(длина) и width(ширина). Требуется реализовать: – 1. Селекторы – 2. Модификаторы, генерирующие исключения Bad. Length. Exception и Bad. Width. Exception если атрибут <= 0 – 3. Функцию main() {…} с блоком try/catch, которая пытается создать прямоугольник с неверными атрибутами и выводит сообщение о соответствующей ошибке в блоке catch.


