Механизм исключений.pptx
- Количество слайдов: 28
Механизм исключений и продолжение шаблонов
Определение методов шаблонного класса template <typename T> class Sample { T field; public: T const& get. Field() const; void set. Field(T other); }; template <typename T> T const& Sample<T>: : get. Field() const { return field; } template <typename T> void Sample<T>: : set. Field(T other) { field = other; }
Разбиение шаблонных классов на файлы • Шаблонные классы не разбиваются на. h и. cpp, весь код шаблонного класса пишется в. h, это связано с тем, что при разделении класса компилятор не сможет инстанциировать шаблон нужным типом в момент компиляции. • Вместо этого поступают следующим образом: для наглядности вместо. cpp создают. hpp (эквивалентен. h) и реализацию внешних методов выносят в. hpp, затем файл. hpp подключают в конец. h
Пример | sample. h #ifndef SAMPLE_GUARD_HEADER #define SAMPLE_GUARD_HEADER template <typename T> class Sample { T field; public: T const& get. Field() const; void set. Field(T other); }; #include "sample_impl. h" #endif
Пример | sample. hpp template <typename T> T const& Sample<T>: : get. Field() const { return field; } template <typename T> void Sample<T>: : set. Field(T other) { field = other; }
Специализация шаблона и перегрузка template <typename T> void foo(T a, T b) { std: : cout << "same types" << std: : endl; } template <typename T, typename V> void foo(T a, V b) { std: : cout << "different types" << std: : endl; } template <> void foo <int, int>(int a, int b) { std: : cout << "both parameters are int" << std: : endl; } int main() { foo(3, 4); }
Нетиповые шаблонные параметры template <typename T, size_t M, size_t N> class Matrix { T data[M][N]; public: //. . . T& operator()(size_t i, size_t j) { return data[i][j]; } };
Шаблонный параметр - шаблон string to. String(int i); // int -> string Array<string> to. String(Array <int> const& ar) { // только с Array <string> result(ar. size); for (size_t i = 0; i != ar. size(); ++i) result. get(i) = to. String(ar. get(i)); return result; } template <typename> class Container> Container <string> to. String(Container <int> const& c) { // для любых контейнеров Container<string> result(c. size()); for (size_t i = 0; i != c. size(); ++i) result. get(i) = to. String(c. get(i)); return result; }
Использование зависимых имён template <typename T> class Array { size_t size; T* data; public: typedef T value_type; }; template <class Container> bool contains(Container const& c, typename Container: : value_type const& c);
Псевдоним шаблона template <typename T> class Sample { T data; public: // interface }; template <typename T> using Sample. Alias = Sample <T>; int main() { Sample. Alias <int*> obj; }
Компиляция шаблонов • Шаблоны независимо компилируются для каждого значения шаблонных параметров • Компиляция (инстанциирование) шаблона происходит в точке первого использования – точке инстанциирования шаблона • Компиляция шаблонов классов – ленивая, компилируются только те методы, которые используются • В точке инстанциирования шаблон должен быть полностью определен • Шаблоны следует определять в заголовочных файлах • Все шаблонные функции являются inline • В разных единицах трансляции инстанциирование происходит независимо
*Модификатор mutable Позволяет константным методам изменять поля объектов class Sample { int field; mutable int const. Methods. Call. Number; public: Sample(int f) : const. Methods. Call. Number(0) { field = f; } void method() const { ++const. Methods. Call. Number; } int get. Const. Methods. Call. Number() const { return ++const. Methods. Call. Number; } };
Способы обработки ошибок • Без обработки ошибок (предусловие) size_t write(string file, DB const& data); • Возврат статуса операции bool write(string file, DB const& data, size_t& bytes); • Возврат кода ошибки enum class Error. Code { OK, IO_FAIL, NET_FAIL }; Error. Code write(string file, DB const& data, size_t& bytes);
Способы обработки ошибки • Использование глобального кода ошибки size_t write(string file, DB const& data); int main() { // some code size_t bytes = write(f, db); if (errno) { std: : cout << strerror(errno); errno = 0; } }
Концепция исключений • Исключение – это объект, содержащий описание ошибки, который передается от места её возникновения к месту обработки • Обработка исключений в С++ использует три ключевых слова: try, catch и throw. Те инструкции программы, где ожидается возможность появления исключительных ситуаций, содержатся в бло ке ry. Если в блоке try возникает исключение, т. е. ошибка, то t генерируется исключение. Исклю чение перехватывается, используя catch, и обрабатывается.
Пример class Wrong. Time. Exception { double incorrect. Time; public: Wrong. Time. Exception(double incorrect. Time. Value) : incorrect. Time(incorrect. Time. Value) { } const char* err. Message() const { return "Wrong time"; } double get. Incorrect. Time() const { return incorrect. Time; } };
Пример | продолжение double speed(double path, double time) { if (time <= 0) { Wrong. Time. Exception exception(time); throw exception; } return path / time; }
Пример | продолжение int main() { double path; double time; std: : cout << "Enter path (km): "; std: : cin >> path; std: : cout << "Enter time (hours): "; std: : cin >> time; try { std: : cout << "Speed = " << speed(path, time) << "km/h" << std: : endl; } catch (Wrong. Time. Exception exception) { std: : cout << exception. err. Message() << ": " << exception. get. Incorrect. Time() << std: : endl; } }
catch для любого исключения catch (Type exc) { } catch (Type 2 exc) { } //. . . catch (. . . ) // отлавливает исключения любого типа { }
Использование throw для передачи исключения выше по стеку вызовов void foo() { throw Some. Exception(); } void giu() { try { foo(); } catch (. . . ) { throw; } } int main() { try{ giu(); } catch (. . . ) { // do something } }
Стандартные классы исключений Базовый класс для всех исключений (в <exception>) class exception { virtual ~exception(); virtual const char* what() const; }; Стандартные классы ошибок (в <stdexcept>) • logic_error: domain_error, invalid_argument, length_error, out_of_range • runtime_error: range_error, overflow_error, underflow_error
Например int main() { try { //. . . } catch (std: : exception const& e) { std: : cout << e. what() << std: : endl; } }
Раскручивание стэка void foo() { D d; E e; throw 42; F f; } void bar() { A a; try { B b; foo(); C c; } catch (int i) { throw; } }
Недопустимость исключений в деструкторе void foo() { D d; E e; // исключение в деструкторе throw 42; F f; } void bar() { A a; try { B b; foo(); C c; } catch (int i) { throw; } }
Исключение в конструкторах Исключение в конструкторе – единственный способ сообщить об ошибке в процессе конструирования объекта class Database { //. . . public: Database(string const& uri) { if(!connect(uri)) throw Network. Error(); } };
Продолжение | Исключения в конструкторе int main() { try { Database *db = new Database(uri); db -> dump(); delete dp; } catch (std: : exception const& e) { // handle exception } }
Исключения в списке инициализаторов class Sample { Field 1 field 1; Field 2 field 2; public: Sample() try : field 1(), field 2() { } catch (std: : exception const& e) { throw; } };
Правила обработки исключений • Обрабатывать ошибки единообразно • Централизованно обрабатывать ошибки в пределах одной логической части кода • Если не известно, как обработать ошибку – переслать её выше • Отлавливать исключения в деструкторах • Осторожно использовать исключения
Механизм исключений.pptx