Надежность ПО: простой план
Напомним, что мы различаем ошибочные и неудобные (нежелательные) условия. Неудобные или нежелательные условия должны обрабатываться обычной программной логикой. Ошибки (дефекты) требуют специального программирования. В книге Страуструпа Язык программирования С++ (1997) автор приводит четыре основных альтернативных действия, которые может предпринять программа при обнаружении ошибки. По мнению Страуструпа, программа, выявив проблему, которую невозможно обработатьлогически, должна реализовать один из следующих вариантов поведения.
• Вариант1. Завершить программу.
• Вариант 2. Возвратить значение, обозначающее «ошибку».
• Вариант 3. Возвратить значение, обозначающее нормальное завершение, и оставить программу в состоянии с необработанной ошибкой.
• Вариант 4. Вызвать функцию, предназначенную для вызова в случае ошибки.
Эти четыре альтернативы можно «примерить» к отношениям типа «изготовитель-потребитель». Изготовитель — это обычно некоторый участок програм м ного кода, который реализует библиотечную функцию, класс, библиотеку классов или оболочку приложения. В качестве потребителя можно представить участок программного кода, который вызывает библиотечную функцию, класс, библиотеку классов или оболочку приложения. Потребитель делает запрос. Изготовитель при попытке выполнить запрос обнаруживает ошибку, и его дальнейшее поведение должно быть направлено на реализацию одного из перечисленных выше четырех альтернативных вариантов. Однако проблема состоит в том, что ни один из них не универсален.
Очевидно, что завершать программу при каждом обнаружении ошибки попросту неприемлемо. Здесь мы согласны со Страуструпом. В таких случалх следует поступать более изобретательно. Что касается варианта 2, то примитивный возврат значения ошибки действительно может помочь в некоторых ситуациях, но далеко не во всех. Не каждое возвращаемое значение может интерпретироваться как успешное или неудачное. Например, если значение, возвращаемое некоторой функцией, имеет вещественный тип, и область определения функции включает как отрицательные, так и положительные значения, то какое тогда значение функции можно использовать для представления ошибки? Другими словами, это не всегда возможно. С нашей точки зрения, вариант 3 также неприемлем. Ведь если «изготовитель» возвращает значение, обозначающее нормальное завершение, «потребитель» продолжит работу, предположив, что его запрос был выполнен, а это может вызвать еще большие проблемы. Осталось рассмотреть вариант 4. Он требует более внимательного подхода при обсуждении обработки как ошибок, так и исключительных ситуаций.
План А: модель возобновления, план Б: модель завершения
При обнаружении ошибки или исключительной ситуации существует два основных плана для реализации варианта4. Первый план состоит в попытке скорректировать условия, которые вызвали сбой, а затем возобновить выполнение с точки, в которой была обнаружена ошибка или исключительнал ситуация. Этот подход называетс я возобновлением. Второй план состоит в признании (подтверждении) ошибки или исключительной ситуации и постепенном выходе из подсистемы или подпрограммы, в которой возникла проблема. Постепенный выход реализуется путем закрытия соответствующих файлов, разрушения требуемых объектов, регистрации (если это возможно) ошибки, освобождения соответствующей памяти и обработки устройств, которые этого требуют. Такой подход называется завершением, и его не следует путать с понятием резкого выхода из программы. Оба плана вполне действенны и в различных ситуациях оказываются весьма полезными. Прежде чем обсуждать способы реализации моделей возобновления и завершения, имеет смысл рассмотреть средства обработки ошибок и исключительных ситуаций, которые прелусмотрены в языке С++.
Использование объектов отображения для обработки ошибок
Компонент отображения (map)можно использовать как составную часть стратегии обработки ошибок или обработки исключений. Назначение отображения — связать один элемент с другим. Например, отображение можно использовать для связи номеров ошибок с их описаниями:
//.. .
map ErrorTable;
ErrorTable[123] = «Деление на нуль»;
ErrorTable[4556] = «Отсутствие тонального вызова»;
//. . .
Здесь число 123 связано с описанием «Деление на нуль». Тогда при выполнении инструкции
Читать дальше