Исключения как механизм обработки ошибок Варианты обработки ошибок без исключений: 1.Умолчание ошибки int atoi ( const char * str ); const char * strVal.

Презентация:



Advertisements
Похожие презентации
Исключения в Java Макаревич Л. Г.. Исключения – это механизм взаимодействия между кодом, приведшим к ошибке, и кодом, обрабатывающим ошибку Исключение.
Advertisements

Преобразование типов Макаревич Л. Г.. Операция приведения типов Тип ( выражение ) Тип ( выражение ) (тип) выражение (тип) выражение int a = 5; float b.
Обработка исключений Основы метапрограммированияОбработка исключений Основы метапрограммирования.
Функции с переменным числом аргументов private static int Sum(int a, int b) { return a + b; } static void Main() { int sum = Sum(1, 2); } 1 Функции.
Объектно-ориентированное программирование С++. Лекция 9 Карпов В.Э.
C++ templates. Синтаксис template void f(const T& value) { std::cout << "Value is: " << value << std::endl; } template struct Array { T data[n]; };
Test 14 Вопрос 1. class Main { public void method() { static class One { public One() { System.out.println("From one"); } } public static void main(String...
НГТУ, каф. ВТ Исключения в С++ Макаревич Л. Г.. Что такое исключение Исключение или исключительная ситуация – возникновение непредвиденных или аварийных.
Обработка исключительных ситуаций Исключительная ситуация (исключение) – это ошибка, возникающая во время выполнения программы. Например, ошибка работы.
1 A + B Операнд 1Операнд 2 Оператор Что такое выражение (expression) ? Что такое инструкция (statement) ? Операторы int max = (a > b) ? a : b;
Test 10 Вопрос 1. public class Test implements Iterator { // 1 private List list = new ArrayList (); // 2 public void addList(T... ts) { Collections.addAll(list,
Язык C++ Лекция 2. Недостатки enumов Засорение namespaceа, в котором находится enum Соответственно, члены enumа должны иметь уникальный префикс.
Стеки и очереди 1. Абстрактный стек public interface Stack { static class Underflow extends Exception { public Underflow() { super("Stack underflow");
Test 16 Вопрос 1. class Clazz { { System.out.println("non-static init"); } public static void main(String a[]) { System.out.println("main"); Clazz ob1.
Перегрузка операторов x = a + b результат 1-й операнд2-й операнд оператор По количеству операндов операторы делятся на: унарные (один операнд) бинарные.
Unit II Constructor Cont… Destructor Default constructor.
Шаблоны в С++ Макаревич Л. Г.. Шаблоны функций Многие алгоритмы не зависят от типов данных. Многие алгоритмы не зависят от типов данных. #include using.
1. Классы ООП 1.Наследование 2.Инкапсуляция 3.Полиморфизм.
Лекция 4. Введение в С++ Наследование, множественное наследование. Конструкторы, деструкторы. Виртуальные функции.
Test 11 Вопрос 1. class HashTest { private static Set set = new LinkedHashSet (); public static void main(String[] args) { set.add("one"); set.add("two");
Транксрипт:

Исключения как механизм обработки ошибок Варианты обработки ошибок без исключений: 1.Умолчание ошибки int atoi ( const char * str ); const char * strVal = abc; … const int val = atoi(strVal); // результат функции 0 2. Возвратить результат операции bool strToInt(const char * str, int & out); const char * strVal = abc; … int val = 0; strToInt(strVal, val); // Результат операции не проверяется

3. Выставить глобальный флаг ошибки int errorFlag; #define ERR_NO_ERROR #define ERR_INCORRECT_INPUT … int strToInt(const char * str) { errorFlag = ERR_NO_ERROR; … errorFlag = ERR_INCORRECT_INPUT; return 0; … } int main() { … const int val = strToInt (strVal); // функция вернет 0 If (errorFlag != ERR_NO_ERROR) { … } … }

Базовый синтаксис try..catch…throw try { throw T1(); … throw T2(); … throw T3(); } catch(T1 t1) { … } catch(T2 t2) { … } catch (…) // все типы исключений { }

class InputError { … }; int strToInt(const char * str) { … throw InputError(); … } int main() { … try { …. const int value = strToInt(strValue); … } catch(InputError error) { std::cout

Исключение – это один из способов передачи управления int fun() { … return 0; … } int fun() { … throw std::runtime_error(); … } int fun2() { … fun(); … } try { fun2(); } catch(std::runtime_error & err) { }

Особенности обработчика catch try { throw E(); } catch(H) { … } Обработчик catch (H) будет вызван, если: 1.Если Н того же типа что и Е; 2.Если Н является открытой базой Е; 3.Будет выполнено для указателей и ссылок если выполняется [1] или [2];

Особенности обработчика catch try { throw 4; // выбросили исключение типа int } catch(int errNum) // попали в обработчик исключения типа int { … } Обработчик catch (H) будет вызван, если: 1.Если Н того же типа что и Е 2.Если Н является открытой базой Е 3.Будет выполнено для указателей и ссылок если выполняется [1] или [2]

Особенности обработчика catch try { throw std::runtime_error; } catch(std::exception err) { … } Обработчик catch (H) будет вызван, если: 1.Если Н того же типа что и Е 2.Если Н является открытой базой Е 3.Будет выполнено для указателей и ссылок если выполняется [1] или [2] std::exception std::runtime_error

Перехват всех исключений и повторная генерация try { … } catch(…) // перехватить все типы исключений { … throw; //выброcить еще раз то же самое исключение … }

Порядок следования catch - секций try { } catch (int numErr) { … } catch (std::exception exc) {... } catch(std::runtime_error exc) {... } std::exception std::runtime_error

Порядок следования catch - секций try { throw std::runtime_error (); } catch(std::runtime_error exc) // сработает { } catch (std::exception exc) { } catch(…) { } std::exception std::runtime_error

Иерархия классов исключений и секция catch try { throw SpecialException(); } catch (BaseException exc) { cout

Иерархия классов исключений и секция catch try { throw SpecialException(); } catch (const BaseException & exc) { cout

Принцип RAII и исключения RAII - Resource Acquisition Is Initialization

bool fun() { … Dictionary * dict = new Dictionary(); If (!dict->loadDictionary(path)) { delete dict; return false; } EncodingConverter * converter = new EncodingConverter (); If (!converter->init()) { delete dict; delete converter ; return false; } OperationController *controller = new OperationController(dict, converter); If (!controller->init()) { delete dict; delete converter ; delete controller ; return false; } // некоторые действия и также вызов освобождение dict, converter, controller }

void fun() { // захватить ресурс 1 // захватить ресурс 2 … // захватить ресурс N // использование ресурсов // освободить ресурс 1 // освободить ресурс 2 … // освободить ресурс N }

Решение 1 bool fun() { … Dictionary * dict = new Dictionary(); EncodingConverter * converter = new EncodingConverter (); OperationController controller = new OperationController(dict, converter); try { If (!dict->loadDictionary(path)) throw DictionaryInitError(); … } catch(…) { delete dict; delete converter ; delete controller ; return false; } delete dict; … return true; }

Решение 2 class AutoDictionary { public: AutoDictionary(Dictionary * dict) : mDict(dict) { } ~AutoDictionary() { delete mDict;} Dictionary *operator->() { return mDict; } private: Dictionary * mDict; };

Решение 2 void fun() { … AutoDictionary dict(new Dictionary()); AutoEncodingConverter converter(new EncodingConverter ()); AutoOperationController controller (new OperationController(dict.get(), converter.get())); if (!dict->loadDictionary(path)) throw DictionaryInitError(); if (!converter->init()) throw ConverterInitError(); if (!controller->init()) throw ControllerinitError(); … }

Решение 3 void fun() { … std::auto_ptr dict(new Dictionary()); std::auto_ptr converter(new EncodingConverter ()); std::auto_ptr controller (new OperationController(dict.get(), converter.get())); If (!dict->loadDictionary(path)) throw DictionaryInitError(); If (!converter->init()) throw ConverterInitError(); If (If (!controller->init()) throw ControllerinitError(); … }

bool fun() { … std::auto_ptr dict(new Dictionary()); std::auto_ptr converter(new EncodingConverter ()); std::auto_ptr controller (new OperationController(dict.get(), converter.get())); if (!dict->loadDictionary(path)) return false; if (!converter->init()) return false; if (!controller->init()) return false; … }

преобразования типов void fun(double val); … fun(1); // будет вызвана fun(double val); fun(1.0); … try { throw 1; //генерация int - исключения } catch(double) // обработчик для double типа { … // не сработает для int } Допускается для: 1.Для наследуемых типов; 2.Из типизированного в нетипизированный указатель (void * ); try { throw Error; // тип cont char * throw new std::runtime_error(); // тип std::runtime_error * } catch(void * ptr) // перехватить все исключения типа указатель { … }

Неперехваченные исключения int main() { throw 4; } int main() { try { … } catch(…) { … } std::terminate() -> abort()

Спецификация исключений на уровне определения функций void fun() throw (x1, x2); void fun() throw (std::runtime_error, int); void fun() { try { } catch (std::runtime_error) { throw; } catch (int) { throw; } catch(…) { std::unexpected(); } std::unexpected() - >std::terminate() -> abort()

void f(); // может генерировать любое исключение void f() throw(); // не генерирует исключений void f() throw(std::exception, int); // генерирует исключения типа int, std::exception и // производные от std::exception void fun() throw() { throw 1; } int main() { fun(); return 0; }

class A { public: virtual ~A() { } virtual void f(); virtual void g() throw(X, Y); virtual void h() throw(X); }; class B : public A { public: virtual void f() throw(X); virtual void g() throw(X); virtual void h() throw(X, Y); };

Неожиданные исключения и std::bad_exception 1. std:: bad_exception void f() throw(X, std::bad_exception) { … throw 1; //выбрасываем исключение типа int (будет выброшено std::bad_exception) … } 2. unexpected_handler typedef void(*unexpected_handler); unexpected_handler set_unexpected(unexpected_handler) throw( );

Исключения в конструкторах Без использования исключений: 1.Сконструировать объект с некорректным состоянием class A { public: A(); bool isValidConstructed() const; }; … A a; If (!a. isValidConstructed()) { … } …

2. Присвоить значение глобальной переменной; 3. Не делать инициализации в конструкторе и сделать отдельную функцию инициализации. class A { public: A() {} bool init(); };

4.Пометить объект как неинициализированный и во всех функциях проверять состояние объекта; … const int gErrCodeInitError=-2; … class A { public: A() { … mInitialized = false; … } int fun() { If (! mInitialized ) return gErrCodeInitError; … } private: bool mInitialized; };

class DBConnectionWrapper { public: DBConnectionWrapper(const std:string & username, const std::string & psw) : mConnection(NULL) { mConnection = new db::DBConnection(); std::string error; if (mConnection->connect(username, psw, error)) throw DBConnectionFailed(error); } … private: db::DBConnection * mConnection; }; try { DBConnectionWrapper dbConnectionWrapper (username, psw); … } catch(DBConnectionFailed & exc) …

class DBConnectionWrapper { public: DBConnectionWrapper(const std:string & username, const std::string & psw) : mConnection(NULL) { mConnection = new db::DBConnection(); std::string error; if (mConnection->connect(username, psw, error)) throw DBConnectionFailed(error); } ~ DBConnectionWrapper() { delete mConnection; // Не сработает, если в конструкторе было исключение } … private: db::DBConnection *mConnection; }; Удаляются только полностью сконструированные объекты!!!

class DBConnectionWrapper { public: DBConnectionWrapper(const std:string & username, const std::string & psw) : mConnection(NULL) { try { mConnection = new db::DBConnection(); std::string error; if (mConnection->connect(username, psw, error)) throw DBConnectionFailed(error); } catch(…) { delete mConnection ; throw; } … private: db::DBConnection *mConnection; };

class DBConnectionWrapper { public: DBConnectionWrapper(const std:string & username, const std::string & psw) try : mConnection(NULL) { mConnection = new db::DBConnection(); std::string error; if (mConnection->connect(username, psw, error)) throw DBConnectionFailed(error); } catch(…) { delete mConnection ; throw; } … private: db::DBConnection *mConnection; };

class DBConnectionWrapper { public: DBConnectionWrapper(const std:string & username, const std::string & psw) : mConnection(new db::DBConnection()) { std::string error; if (mConnection->connect(username, psw, error)) throw DBConnectionFailed(error); } … private: AutoConnection mConnection; }; AutoConnection { public: AutoConnection(db::DBConnection *connection) : mConnection(connection) { } ~AutoConnection() { delete mConnection; } db::DBConnection * operator->() { return mConnection; } private: db::DBConnection * mConnection; };

Использование smart pointer class DBConnectionWrapper { public: DBConnectionWrapper(const std:string & username, const std::string & psw) : mConnection(new db::DBConnection()) { std::string error; if (mConnection->connect(username, psw, error)) throw DBConnectionFailed(error); } … private: std::auto_ptr mConnection; };

Исключения в деструкторах class DBConnectionWrapper { public: DBConnectionWrapper(const std:string & username, const std::string & psw); ~DBConnectionWrapper() { mConnection->close(error); // может быть сгенерировано исключение } private: std::auto_ptr mConnection; }; Деструктор объекта вызывается в следующих случаях: 1.Выход из области видимости или оператор delete; 2.В процессе обработки исключения: в процессе раскручивания стека;

Деструктор объекта вызывается в следующих случаях: 1.Выход из области видимости или оператор delete; 2.В процессе обработки исключения: в процессе раскручивания стека; void makeQuery(std::string sql) { … DBConnectionWrapper connection(username, psw); … If (!connection.query(sql)) throw QueryFailed(); // автоматически будет вызван ~DBConnectionWrapper … }

class DBConnectionWrapper { public: DBConnectionWrapper(const std:string & username, const std::string & psw); ~DBConnectionWrapper() { try { mConnection->close(error); // может быть сгенерировано исключение } catch(…) { } private: std::auto_ptr mConnection; };

Стандартные исключения exception logic_errorruntime_error length_error domain_error out_of_range invalid_argument bad_alloc bad_exception io_base::failure bad_typeid bad_cast range_error overflow_error underflow_error

1. std::bad_alloc SomeClass sc = new SomeClass(); // может быть сгенерировано исключение std::bad_alloc 2. std::bad_cast B & b = dynamic_cast (a); // может быть сгенерировано исключение std::bad_cast 3. std::bad_exception Для спецификации исключений

Гарантия безопасности исключений Уровни гарантий: 1. no throw guarantee; 2. strong exception safety (commit or rollback semantics); 3. basic exception safety; 4. Minimal exception safety; 5. No exception safety;

class Node { int mData; Node * mPNext; } class IntList { public: … void add(int value) { mCachedSize ++; Node * node = new Node(); // возможно исключение std::bad_alloc … } … Unsigned int size() const { return mCachedSize; } private: … unsigned int mCachedSize; }; 1. no throw guarantee; 2. strong exception safety (commit or rollback semantics); 3. basic exception safety; 4. Minimal exception safety; 5. No exception safety;

class Node { int mData; Node * mPNext; } class IntList { public: … void add(int value) throw (std::bad_alloc) { mCachedSize ++; // некорректное значение размера Node * node = new Node(); // возможно исключение std::bad_alloc … } … Unsigned int size() const { return mCachedSize; } private: … unsigned int mCachedSize; }; 1. no throw guarantee; 2. strong exception safety (commit or rollback semantics); 3. basic exception safety; 4. Minimal exception safety; 5. No exception safety;

class Node { int mData; Node * mPNext; } class IntList { public: … void add(int value) throw (std::bad_alloc) { Node * node = new Node(); // возможно исключение std::bad_alloc … mCachedSize ++; // Увеличить размер только после полностью завершенной // операции } … Unsigned int size() const { return mCachedSize; } private: … unsigned int mCachedSize; }; 1. no throw guarantee; 2. strong exception safety (commit or rollback semantics); 3. basic exception safety; 4. Minimal exception safety; 5. No exception safety;

class T1; class T2; class A { public: … A & operator=(const A & obj) { mT1 = obj.mT1; mT2 = obj.mT2; return *this; } … private: T1 mT1; T2 mT2; }; 1. no throw guarantee; 2. strong exception safety (commit or rollback semantics); 3. basic exception safety; 4. Minimal exception safety; 5. No exception safety; Гарантия безопасности и operator=

class T1; class T2; class A { public: … A & operator=(const A & obj) { mT1 = obj.mT1; mT2 = obj.mT2; // может произойти исключение return *this; } … private: T1 mT1; T2 mT2; }; 1. no throw guarantee; 2. strong exception safety (commit or rollback semantics); 3. basic exception safety; 4. Minimal exception safety; 5. No exception safety; Гарантия безопасности и operator=

class A { public: … A & operator=(const A & obj) { A tmp(obj); swap(tmp); return *this; } … private: void swap(A & a) throw(); T1 mT1; T2 mT2; }; 1. no throw guarantee; 2. strong exception safety (commit or rollback semantics); 3. basic exception safety; 4. Minimal exception safety; 5. No exception safety; Гарантия безопасности и operator=