Чтение онлайн

на главную - закладки

Жанры

Параллельное и распределенное программирование на С++
Шрифт:

Рис. 7.3. Архитектура упрощенного компонента обработки ошибок

Компонент 1 на рис. 7.3— это простой компонент отображения (map), который содержит список номеров ошибок и их описания. Компонент 2 содержит объект, который преобразует номера ошибок в адреса переходов, функций или подсистем. По номеру ошибки компонент 2 определяет направление перехода. Компонент 3 преобразует номера ошибок в иерархическую структуру отчетов и логику отчетов. Иерархическая структура отчетов содержит данные о том, кого (или что) необходимо уведомить об ошибке. Логика отчетов определяет, что должно включать это уведомление. Компонент 4

содержит два объекта отображения. Первый преобразует номера ошибок в объекты, назначение которых — скорректировать некоторые ситуации сбоя (условия). Второй преобразует номера ошибок в объекты, которые возвращают систему в стабильное или хотя бы частично стабильное состояние. Упрощенный компонент обработки ошибок, показанный на рис. 7.3, можно применить к ПО любого размера и формы. Характер использования компонентов обработки ошибок и исключительных ситуаций определяется требуемой степенью надежности ПО.

Надежность ПО: простой план

Напомним, что мы различаем ошибочные и неудобные (нежелательные) условия. Неудобные или нежелательные условия должны обрабатываться обычной программной логикой. Ошибки (дефекты) требуют специального программирования. В книге Страуструпа Язык программирования С++ (1997) автор приводит четыре основных альтернативных действия, которые может предпринять программа при обнаружении ошибки. По мнению Страуструпа, программа, выявив проблему, которую невозможно обработатьлогически, должна реализовать один из следующих вариантов поведения.

• Вариант1. Завершить программу.

• Вариант 2. Возвратить значение, обозначающее «ошибку».

• Вариант 3. Возвратить значение, обозначающее нормальное завершение, и оставить программу в состоянии с необработанной ошибкой.

• Вариант 4. Вызвать функцию, предназначенную для вызова в случае ошибки.

Эти четыре альтернативы можно «примерить» к отношениям типа «изготовитель-потребитель». Изготовитель — это обычно некоторый участок програм м ного кода, который реализует библиотечную функцию, класс, библиотеку классов или оболочку приложения. В качестве потребителя можно представить участок программного кода, который вызывает библиотечную функцию, класс, библиотеку классов или оболочку приложения. Потребитель делает запрос. Изготовитель при попытке выполнить запрос обнаруживает ошибку, и его дальнейшее поведение должно быть направлено на реализацию одного из перечисленных выше четырех альтернативных вариантов. Однако проблема состоит в том, что ни один из них не универсален.

Очевидно, что завершать программу при каждом обнаружении ошибки попросту неприемлемо. Здесь мы согласны со Страуструпом. В таких случалх следует поступать более изобретательно. Что касается варианта 2, то примитивный возврат значения ошибки действительно может помочь в некоторых ситуациях, но далеко не во всех. Не каждое возвращаемое значение может интерпретироваться как успешное или неудачное. Например, если значение, возвращаемое некоторой функцией, имеет вещественный тип, и область определения функции включает как отрицательные, так и положительные значения, то какое тогда значение функции можно использовать для представления ошибки? Другими словами, это не всегда возможно. С нашей точки зрения, вариант 3 также неприемлем. Ведь если «изготовитель» возвращает значение, обозначающее нормальное завершение, «потребитель» продолжит работу, предположив, что его запрос был выполнен, а это может вызвать еще большие проблемы. Осталось рассмотреть вариант 4. Он требует более внимательного подхода при обсуждении обработки как ошибок, так и исключительных ситуаций.

План А: модель возобновления, план Б: модель завершения

При обнаружении ошибки или исключительной ситуации существует два основных плана для реализации варианта4. Первый план состоит в попытке скорректировать условия, которые вызвали сбой, а затем возобновить выполнение с точки, в которой была обнаружена ошибка или исключительнал ситуация. Этот подход называетс я

возобновлением. Второй план состоит в признании (подтверждении) ошибки или исключительной ситуации и постепенном выходе из подсистемы или подпрограммы, в которой возникла проблема. Постепенный выход реализуется путем закрытия соответствующих файлов, разрушения требуемых объектов, регистрации (если это возможно) ошибки, освобождения соответствующей памяти и обработки устройств, которые этого требуют. Такой подход называется завершением, и его не следует путать с понятием резкого выхода из программы. Оба плана вполне действенны и в различных ситуациях оказываются весьма полезными. Прежде чем обсуждать способы реализации моделей возобновления и завершения, имеет смысл рассмотреть средства обработки ошибок и исключительных ситуаций, которые прелусмотрены в языке С++.

Использование объектов отображения для обработки ошибок

Компонент отображения (map) можно использовать как составную часть стратегии обработки ошибок или обработки исключений. Назначение отображения — связать один элемент с другим. Например, отображение можно использовать для связи номеров ошибок с их описаниями:

//.. .

map<int,string> ErrorTable;

ErrorTable[123] = «Деление на нуль»;

ErrorTable[4556] = «Отсутствие тонального вызова»;

//. . .

Здесь число 123 связано с описанием «Деление на нуль». Тогда при выполнении инструкции

cout « ErrorTable[123] « endl;

в объект выходного потока cout будет записана строка «Деление на нуль».

Помимо отображения встроенных типов данных, можно также отображать (т.е. находить соответствие) определенные пользователем объекты, содержащие данные встроенных типов. Вместо того, чтобы некоторое отображение просто возвращало описательное сообщение для каждого номера ошибки, можно позаботиться о том, чтобы оно возвращало объект с соответствующим номером ошибки. Этот объект может иметь методы, предназначенные для коррекции ошибок, составления отчетов об ошибках и их регистрации (записи ошибок в системный журнал). Например, предположим, что у нас есть следующий определенный пользователем объект:

defect_response:

class defect_response{

protected: //. . .

int DefectNo;

string Explanation;

public:

bool operator<(defect_response &X);

virtual int doSomething(void); string explanation(void);

//...

};

Теперь мы можем внести в отображение объекты типа defect_response:

//...

map<int,defect_reponse *> ErrorTable;

defect_response * Response;

Response = new defect_response;

ErrorTable[123] = Response;

//...

Этот код связывает объект отклика (на ошибку) с номером ошибки 123. Благодаря полиморфизму объект отображения может содержать указатели на любой объект типа defect_response или любой объект, который выведен из него. Предположим, что у нас есть следующий класс:

class exception_response : public defect_response{

//.. . public:

int doSomething(void)

//...

};

Этот класс exception_response является потомко м класса defect_response, поэтому мы можем внести в объект ErrorTable указатели на тип exception_re sponse.

//...

map<int,defect_reponse *> ErrorTable;

defect_response * Response;

exception_response *Response2;

Response = new defect_response;

Respone2 = new exception_response;

ErrorTable[123] = Response; // Хранит объект типа

// defect_response.

ErrorTable[456] = Response2; // Хранит объект типа

// exception_response.

//...

Это определение означает, что объект типа ErrorTable может связывать с соответствующим но м ером ошибки различные объекты (с различными описаниями и характеристиками). Следовательно, при вызове метода doSomething объект ProblemSolver будет выполнять различные наборы инструкций:

Поделиться:
Популярные книги

Свадьба по приказу, или Моя непокорная княжна

Чернованова Валерия Михайловна
Любовные романы:
любовно-фантастические романы
5.57
рейтинг книги
Свадьба по приказу, или Моя непокорная княжна

Сборник коротких эротических рассказов

Коллектив авторов
Любовные романы:
эро литература
love action
7.25
рейтинг книги
Сборник коротких эротических рассказов

Отец моего жениха

Салах Алайна
Любовные романы:
современные любовные романы
7.79
рейтинг книги
Отец моего жениха

Вадбольский

Никитин Юрий Александрович
1. Вадбольский
Фантастика:
попаданцы
5.00
рейтинг книги
Вадбольский

Бастард Императора. Том 7

Орлов Андрей Юрьевич
7. Бастард Императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 7

Повелитель механического легиона. Том VIII

Лисицин Евгений
8. Повелитель механического легиона
Фантастика:
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Повелитель механического легиона. Том VIII

В зоне особого внимания

Иванов Дмитрий
12. Девяностые
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
В зоне особого внимания

Таня Гроттер и магический контрабас

Емец Дмитрий Александрович
1. Таня Гроттер
Фантастика:
фэнтези
8.52
рейтинг книги
Таня Гроттер и магический контрабас

Бастард Императора. Том 2

Орлов Андрей Юрьевич
2. Бастард Императора
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бастард Императора. Том 2

Кодекс Крови. Книга ХI

Борзых М.
11. РОС: Кодекс Крови
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Кодекс Крови. Книга ХI

Третий

INDIGO
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий

Возвышение Меркурия. Книга 16

Кронос Александр
16. Меркурий
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 16

Идеальный мир для Лекаря 9

Сапфир Олег
9. Лекарь
Фантастика:
боевая фантастика
юмористическое фэнтези
6.00
рейтинг книги
Идеальный мир для Лекаря 9

Потусторонний. Книга 1

Погуляй Юрий Александрович
1. Господин Артемьев
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Потусторонний. Книга 1