- •6.050201 «Системная инженерия»
- •Донецк, 2012
- •1 Цели и задачи дисциплины
- •2 Теоретические основы программирования
- •2.1 Основные сведения в области информатики Общее понятие алгоритма
- •Алгоритмические языки
- •Типы переменных
- •Целочисленные переменные
- •Кольцо вычетов по модулю m
- •Интерпретация положительных и отрицательных чисел
- •Вещественные переменные
- •Машинный эпсилон
- •Запись вещественных констант
- •Символьные переменные
- •Логические переменные и выражения
- •Массивы
- •Текстовые строки
- •Оперативная память
- •Процессор
- •Cisc и risc-процессоры
- •Алгоритм работы компьютера
- •Аппаратный стек
- •Команды вызова подпрограммы call и возврата return
- •Аппаратный стек и локальные переменные подпрограммы
- •2.2. Стандарты построения блок-схем алгоритмов
- •4 Компиляция и выполнение программ
- •5 Структурное программирование
- •5.1 Описание переменных
- •Константы
- •Целые числа
- •Вещественные числа
- •Логические величины
- •Символы и байты
- •Кодировка, многобайтовые символы
- •5.2 Основные операции и их приоритет
- •Порядок вычисления выражений
- •5.3 Операторы
- •Операторы цикла
- •5.4 Организация ввода-вывода
- •Манипуляторы и форматирование ввода-вывода
- •Строковые потоки
- •Ввод-вывод файлов
- •5.5 Массивы
- •5.6. Указатели и операции над ними
- •5.7 Ссылки
- •5.8 Динамическое выделение памяти
- •5.9 Функции
- •Подставляемые функции
- •Имена функций
- •Необязательные аргументы функций
- •Рекурсия
- •Назначение шаблонов
- •Функции-шаблоны
- •5.10 Область видимости имен
- •5.11 Сложные структуры данных
- •5.11.1 Структуры
- •5.11.2 Перечисления
- •5.11.3. Объединения
- •5.12. Динамические структуры данных
- •6 Препроцессор
- •Определение макросов
- •Условная компиляция
- •Дополнительные директивы препроцессора
- •7 Объектно-ориентированное программирование
- •7.1 Основные понятия объектно-ориентированного программирования
- •Определение методов класса
- •Виртуальные методы
- •Виртуальные методы и переопределение методов
- •Преобразование базового и производного классов
- •Внутреннее и защищенное наследование
- •Абстрактные классы
- •Множественное наследование
- •Виртуальное наследование
- •Интерфейс и состояние объекта
- •Объявление friend
- •7.2 Конструктор и деструктор класса
- •Копирующий конструктор
- •Деструкторы
- •Инициализация объектов
- •Операции new и delete
- •7.3 Перегрузка операций
- •Как определять операции
- •Преобразования типов
- •Явные преобразования типов
- •Стандартные преобразования типов
- •Преобразования указателей и ссылок
- •Преобразования типов, определенных в программе
- •7.4 Использование включаемых файлов
- •7.5. Шаблоны классов
- •"Интеллигентный указатель"
- •Задание свойств класса
- •8 Обработка исключительных ситуаций
- •Примеры обработки исключительных ситуаций
- •Список использованных источников
Примеры обработки исключительных ситуаций
Механизм исключительных ситуаций предоставляет гибкие возможности для обработки ошибок, однако им надо уметь правильно пользоваться. В этом параграфе мы рассмотрим некоторые приемы обработки исключительных ситуаций.
Прежде всего, имеет смысл определить для них специальный класс. Простейшим вариантом является класс, который может хранить код ошибки:
class Exception
{
public :
enum ErrorCode {
NO_MEMORY,
DATABASE_ERROR,
INTERNAL_ERROR,
ILLEGAL_VALUE
};
Exception(ErrorCode errorKind,
const String&errMessage);
ErrorCode GetErrorKind(void )const
{return kind;};
const String&GetErrorMessage(void )const
{return msg;};
private :
ErrorCode kind;
String msg;
};
Создание исключительной ситуации будет выглядеть следующим образом:
if (connect(serverName)==false )
throw Exception(Exception::DATABASE_ERROR,
serverName);
А проверка на исключительную ситуацию так:
try {
...
}catch (Exception&e){
cerr <<"Произошла ошибка "<<e.GetErrorKind()
<<"Дополнительная информация:"
<<e.GetErrorMessage();
}
Преимущества класса перед просто целым числом состоят, во-первых, в том, что передается дополнительная информация и, во-вторых, в операторах catch можно реагировать только на ошибки определенного вида. Если была создана исключительная ситуация другого типа, например
throw AnotherException;
то блок catch будет пропущен: он ожидает только исключительных ситуаций типа Exception . Это особенно существенно при сопряжении нескольких различных программ и библиотек – каждый набор классов отвечает только за собственные ошибки.
В данном случае код ошибки записывается в объекте типа Exception . Если в одном блоке catch ожидается несколько разных исключительных ситуаций, и для них необходима разная обработка, то в программе придется анализировать код ошибки с помощью операторов if или switch .
try {
...
}catch (Exception&e){
cerr <<"Произошла ошибка "<<e.GetErrorKind()
<<"Дополнительная информация:"
<<e.GetErrorMessage();
if (e.GetErrorKind()==Exception::NO_MEMORY ||
e.GetErrorKind()==
Exception::INTERNAL_ERROR)
throw ;
else if (e.GetErrorKind()==
Exception::DATABASE_ERROR)
return TRY_AGAIN;
else if (e.GetErrorKind()==
Exception::ILLEGAL_VALUE)
return NEXT_VALUE;
}
Другим методом разделения различных исключительных ситуаций является создание иерархии классов – по классу на каждый тип исключительной ситуации.
Рис. 8.1 - Пример иерархии классов для представления исключительных ситуаций.
В приведенной на рис. 8.1 структуре классов все исключительные ситуации делятся на ситуации, связанные с работой базы данных (класс DatabaseException ), и внутренние ошибки программы (класс InternalException ). В свою очередь, ошибки базы данных бывают двух типов: ошибки соединения (представленные классом ConnectDbException ) и ошибки чтения (ReadDbException ). Внутренние исключительные ситуации и разделены на нехватку памяти (NoMemoryException )и недопустимые значения (IllegalValException ).
Теперь блок catch может быть записан в следующем виде:
try {
}catch (ConnectDbException&e ){
//обработка ошибки соединения с базой данных
}catch (ReadDbException&e){
//обработка ошибок чтения из базы данных
}catch (DatabaseException&e){
//обработка других ошибок базы данных
}catch (NoMemoryException&e){
//обработка нехватки памяти
}catch (…){
//обработка всех остальных исключительных
//ситуаций
}
Напомним, что когда при проверке исключительной ситуации на соответствие аргументу оператора catch проверка идет последовательно до тех пор, пока не найдется подходящий тип. Поэтому, например, нельзя ставить catch для класса DatabaseException впереди catch для класса ConnectDbException – исключительная ситуация типа ConnectDbException совместима с классом DatabaseException (это ее базовый класс), и она будет обработана в catch для DatabaseException и не дойдет до блока с ConnectDbException .
Построение системы классов для разных исключительных ситуаций на стадии описания ошибок – процесс более трудоемкий, приходится создавать новый класс для каждого типа исключительной ситуации. Однако с точки зрения обработки он более гибкий и позволяет писать более простые программы.
Чтобы облегчить обработку ошибок и сделать запись о них более наглядной, описания методов и функций можно дополнить информацией, какого типа исключительные ситуации они могут создавать:
class Database
{
public :
Open(const char*serverName)
throw ConnectDbException;
};
Такое описание говорит о том, что метод Open класса Database может создать исключительную ситуацию типа ConnectDbException . Соответственно, при использовании этого метода желательно предусмотреть обработку возможной исключительной ситуации.
В заключение приведем несколько рекомендаций по использованию исключительных ситуаций.
При возникновении исключительной ситуации остаток функции или метода не выполняется. Более того, при обработке ее не всегда известно, где именно возникла исключительная ситуация. Поэтому прежде чем выполнить оператор throw , освободите ресурсы, зарезервированные в текущей функции. Например, если какой-либо объект был создан с помощью new , необходимо явно вызвать для него delete .
Избегайте использования исключительных ситуаций в деструкторах. Деструктор может быть вызван в результате уже возникшей исключительной ситуации при откате вызовов функций и методов. Повторная исключительная ситуация не обрабатывается и завершает выполнение программы.
Если исключительная ситуация возникла в конструкторе объекта, считается, что объект сформирован не полностью, и деструктор для него вызван не будет.