
- •1. Понятие класса. Методы класса. Управление доступом к компонентам.
- •2. Объявление и определение класса. Внешнее определение функций.
- •3. Создание, копирование и удаление объекта.
- •4. Статические компоненты класса. Инициализация статических компонентов класса.
- •5. Наследование. Типы наследования. Виртуальное наследование.
- •6. Виртуальные функции
- •7. Абстрактные классы и чистые виртуальные функции. Интерфейс
- •8. Дружественность. Дружественные классы и функции.
- •9. Вложенные классы. Внутреннее и внешнее определение.
- •10. Шаблоны классов
- •11.Создание экземпляров шаблона. Инстанцирование.
- •12.Шаблоны и наследование.
- •13.Терминология шаблонов.
- •14. Параметры и аргументы шаблона.
- •15. Шаблоны компонентных функций
- •16. Полная специализация шаблонов.
- •17. Частичная специализация шаблонов.
- •18. Перегрузка операций. Основные понятия.
- •19. Перегрузка унарных операций.
- •20. Перегрузка бинарных операций.
- •Int test() {
- •Int test() {
- •Int test() {
- •// Делаем что-то
- •Вопрос 23
- •24. Группировка и композиция исключений. Повторная генерация. Перехват всех исключений.
- •25. Автоматическое управление ресурсами. Методика raii.
- •Void f() { FileOpen("myfile.Txt", "rt"); //здесь выполняем нужную работу с файлом //... }
- •Void f (int a) throw (x2, x3)
- •27. Стандартная библиотека. Организация стандартной библиотеки
- •28. Тип вектора. Вложенные типы. Итераторы. Доступ к элементам
- •29.Тип Вектора. Конструкторы. Операции со стеком. Списочные операции. Размеры и емкость.
- •30. Стандартные контейнеры. Вопросы производительности операций.
- •31. Процесс разработки по. Цели и этапы проектирования.
- •32. Процесс разработки по. Выявление классов. Определение операций.
- •33. Процесс разработки по. Определение взаимосвязей. Определение интерфейсов.
- •Этап 3: выявление зависимостей
- •Этап 4: определение интерфейсов
- •34. Паттерны проектирования. Основные паттерны.
- •35. Тестирование по. Методы тестирования.
Void f() { FileOpen("myfile.Txt", "rt"); //здесь выполняем нужную работу с файлом //... }
26. Спецификации исключений. Неожиданные исключения
1. Спецификации исключений
Генерация и перехват исключений воздействуют на механизм, которым функция взаимодействует с другими функциями. Поэтому небесполезно использовать спецификацию исключений (exception spesification), для чего нужно в объявлении функции указать набор исключений, который она может породить. То есть, спецификация исключений - это явное описание тех типов исключений, которые могут быть сгенерированы некой функцией. Например:
Void f (int a) throw (x2, x3)
Это объявление специфицирует, что функция f() может быть источником исключений типа х2, х3 и производных от них типов, и никаких других типов исключений. Объявленная таким образом функция предоставляет своим пользователям определенные гарантии. Если во время своего выполнения она попробует произвести действия, нарушающие объявленную гарантию, такая попытка приведет к вызову стандартной функции std::unexpected(). По умолчанию, функция std::unexpected() вызывает std::terminate(), а та в свою очередь, вызывает abort().
По сути, следующий код
Void f() throw (x2, x3)
{
…
}
Эквивалентен
Void f()
Try
{
…
}
Catch (x2) {throw; } //генерируем повторно
Catch (x3) {throw; } //генерируем повторно
Catch (…) {std::unexpected();}
Важным преимуществом рассмотренной спецификации исключений является тот факт, что объявление функции видимо всем ее пользователям (является частью спецификации ее интерфейса), а определение функции – нет.
Кроме того, предполагается, что функция, объявленная без спецификации исключений может порождать любое исключение. Например:
Int f(); //может генерировать любые исключения
Функция, не порождающая никаких исключений, может быть объявлена следующим образом:
Int g () throw(); //не генерирует исключений
Невозможно выявить абсолютно все нарушения спецификации интерфейса на этапе компиляции. Тем не менее, на этом этапе выполняется весьма существенная проверка. Если некоторое объявление функции содержит спецификацию исключений, то тогда и все ее другие объявления (включая определение) обязаны иметь точно такую же спецификации. Например:
Int f() throw (std::bad_alloc);
Int f() //error: отсутствие спецификации
{
//…
}
Не требуется проверять спецификацию исключений за пределами единицы трансляции. Это могут делать конкретные реализации. Но для больших и долгоживущих программных систем они этого делать не должны, или если уж делают, то тогда им следует детектировать лишь грубейшие ошибки, которые невозможно перехватить на этапе выполнения. Смысл состоит в том, чтобы добавление исключений в каком-либо месте программы не требовало бы тотального обновления спецификаций и перекомпиляции остальных частей программы. Система может функционировать в частично обновленном состоянии, полагаясь на динамическое обнаружение неожиданных исключений на этапе выполнения.
Виртуальная функция может замещаться функцией с не менее ограничительной спецификацией исключений. Например:
Class B
{
Public:
Virtual void f(); //может генерировать любые исключения
Virtual void g() throw (X, Y);
Virtual void h() throw (X);
};
Class D: public B
{
Void f() throw (X); //ok
Void g() throw(X); //ok: D::g() более ограничительно, чем B::g()
Void h() throw (X,Y); //error: D::h() менее ограничительно, чем B::h()
};
Спецификация исключений не является частью типа функции, и в операторе typedef она не допускается. Например:
Typedef void (*PF)() throw(X); //error
2. Неожиданные исключения
Спецификация исключений может приводить к выводу unexpected(). В принципе, такие вызовы нежелательны, кроме как на этапе тестирования. Их можно избежать посредством тщательной организации исключений и спецификаций интерфейсов. Кроме того, вызовы unexpected() могут перехватываться таким образом, что они становятся безвредными.
Исключения хорошо сформированной подсистемы Y часто наследуют от одного класса Yerr. Например, при наличии определения
Class Some_Yerr: public Yerr {/*…*/}
функция, объявленная как
void f() throw (Xerr, Yerr, exception);
будет передавать любое из исключений Yerr вызывающей функции. В частности, функция f() будет обрабатывать любое исключение типа Some_Yerr, передавая его вызывающей функции. В итоге, никакое исключение семейства Yerr не спровоцирует в f() вызов unexpected().
Все исключения стандартной библиотеки наследуются от класса exception.