Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
111
Добавлен:
02.05.2014
Размер:
102.91 Кб
Скачать

Namespace unique_name {

Class A{…};

Class B{…};

};

using namespace unique_name;

A a = new A ( );

Зачем нужен так4ой механизм? Это некоторый способ описания локального для данного файла имен. Если мы описываем пространство имен, оно должно попасть внутрь интерфейса, а неименованное пространство имен – это, как бы, вложенное в наш файл пространство имен. Воспользоваться им откуда-то извне совершенно невозможно. Это эквивалентно тому, что мы опишем все с помощью идентификатора static. В новом стандарте рекомендуют, если Вы пишите заново программу, то лучше static не использовать, а пользоваться неименованным пространством имен. Все это ведет к тому, что рано или поздно в языке появиться механизм настоящей зависимой раздельной трансляции. Сейчас в языке уже есть все, что для этого надо. Осталось сделать только один согласованный шаг (все разработчики должны сделать его одновременно). Скорее всего, уже следующий стандарт языка будет содержать механизм раздельной трансляции на уровне языка, а не на уровне среды разработки, которую каждый реализует по-своему. Правда, механизм шаблонов очень тяжело ложиться на механизм раздельной трансляции.

Глава 8. Исключительные ситуации.

Механизм обработки исключений есть во всех современных ЯП, которые мы рассматриваем. И этот механизм идейно идентичен во всех этих языках. В качестве примера мы будем рассматривать следующие языки.

Ада, С++, Java, C#, Delphi

Java, C#, Delphi переняли механизм обработки ИС (исключительние ситуации) из языка С++, а С++ в свою очередь опирался на язык Ада. Поэтому механизм обработки ИС в этих языка очень похожий. Самый простой он в языке Ада. Концепция ИС в-первые была предложена в языке Ада и, как мы видим, почти без исключения перешла во все современные ЯП.

ИС – это авария, некоторая ошибка в программе, которая может возникнуть по двум причинам, во-первых, из-за ошибок в самой программе (не бывает до конца идеальных программ), во-вторых, из-за ошибок во входных данных, т.е. некоторая ситуация, которая не предусмотрена в нормальном ходе выполнения программы. Одно из определений надежного программирования – это искусство строить надежные системы из ненадежных компонент. При возникновении аварии в современном программировании надежная система может немного деградировать, но перестать работать она не может. ИС – это авария, и надежная система должна эту аварию локализовать и по возможности исправить. Понятие обработки ИС появилось довольно давно, еще в начале 60-х были языки, которые позволяли обрабатывать некоторые нехорошие ситуации. Например, в языке PLI был некоторый набор ИС

Оп имя_ИС

Подвешивалась подпрограмма

OVERFLOW goto <метка>

Х= А * В;

При возникновении ИС делался переход на соответствующий оператор. Если нет обработчика, то при переполнении программа просто слетала, а при обработчике, выдается диагностика об ошибке, и программа как-то разумно завершает работу (это уже наше личное дело, как реагировать на ошибку). Это очень похоже на обработку прерываний от внешних устройств. Проблема была в том, что на событие OVERFLOW вставлялся несколько свой обработчик прерываний, а мсеханизм обработки прерываний низкоуровневый, и обрабатывать ИС было достаточно неудобно. Вторым недостатком явилось то, что в качестве таких ИС фигурировало событие ЕNDFILE, если выполнялось что-то типа GET(p), и натыкались на конец файла, то возбуждалась именно вышеописанная ИС. Называть ситуацию конца файла аварийной как-то странно, потому что файлы, как правило, все-таки кончаются. Рассматривать конец файла как аварию – смешно. Здесь проблема в том, что смешиваются два понытия: ситуация, которая все равно рано или поздно наступит и действительно аварийная ситуация. До сих пор несмотря на то, что идеология ИС – это авария, некоторые программисты продолжают использовать ИС как программный механизм. Исключения нельзя использовать как стандартный прием программирования. Мы будем рассматривать ИС, как реакция на некоторую ошибку, и с этой точки зрения рассмотрим 4 аспекта:

  1. Определение (как определяют исключения)

  2. Возникновение

  3. Распространение

  4. Обработка

На современном этапе во время обработки должен выключаться нормальный порядок вычисления программы и должен запускаться несколько априори заданный ход вычисления. Надо понимать, что обычно ошибка возникает на уровне (логическом уровне программы), который совершенно не компетентен ее обработать. Например, мы хотим открыть файл, а файла не существует, то ли сетевой драйвер отключился, то ли имя файла не правильно было указано, в любом случае в том месте, где мы пытаемся открыть файл, по этому поводу ничего сказать не можем. То ли нужно переподключить сетевой драйв, то ли нужно запросить у пользователя новое имя файла, а ввод данных происходит совершенно на другом уровне программы. Т.е. в месте, где возникла ошибка не всегда есть возможность ее исправить. Этим были плохи ЯП с локальной обработкой ИС. Сейчас возбуждается ИС, и она распространяется до тех пор, пока не выйдет на уровень, который достаточно компетентен, что бы ее обработать. Самый плохой случай, когда ни один уровень не является достаточно компетентным, тогда исключение выскакивает на самый верхний уровень, и самое разумное, что можно сделать, это завершить программу с диагностикой об ошибке. Это, конечно не подходит для надежной системы, но в целях отладки, получим диагностику. Еще одно важное свойство таково, что нормальный код выполнения программы должен быть отделен от код, который исправляет ошибки. Это потому, что в 99 случаях их 100 у нас работает только нормальный код. Программирование на С заставляет смешивать эти код. Следовательно сопровождение и отладка крайне тяжелое занятие. Современные ЯП позволяют нам структурировать, т.е. отделить текстуально код по исправлению ошибок от код, ответственного за нормального выполнения программы. Сначала посмотрим, как это реализовано в языке Ада.

Ада.

1. Определение. В Аде введено специальное ключевое слово exception. Это похоже на описание типов данных, т.е. фактически у нас с исключениями связан контретный тип данных, но его таковым не называют, потому что к нему не применимы почти никакие операции, за исключением возникновения и обработчика. Мы будем считать, что это особый тип данных, который встроен язык. Объекты типа exception мы объявляем как переменные. Например,

FILE_ERROR: exception;

С точки зрения реализации каждое исключение кодируется своим целочисленным идентификатором. Кром6е этого в языке Ада есть предопределенные исключения, например, RANGE_ERROR; мы много говорили о квазистатическом контроле. Например, у нас написано X := A(I); где I индекс, и I выходит за рамки допустимых значений. Вот тогда-то и возникает предопределенное исключение RANGE_ERROR. Не важно, что оно предопределенное, прграммист его все равно может перехватить и обработать. Важно, что не произойдет порча памяти. Кроме предопределенных исключений, пользователь может вводить свои.

2. Возникновение. Для предопределенных исключений компилятор сам вставляет возбуждение ИС, для пользовательских – есть специальный оператор языка Ада

raise имя_исключения , например, raise FILE_ERROR;

Мы знаем, что не смогли открыть файл, но как это исправить на данном уровне не знаем, поэтому просто сигнализируем.

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

Pr P

x

Pr P1

x

Pr P2

x

P3 Статическая область видимости

Pr P3

Динамическая область видимости

Все ЯП, которые мы рассматриваем, со статической областью видимости, а для исключений ситуация немного другая. Они обладают именно динамической областью видимости. Считается, что исключение произошло именно в программном блоке, под которым понимается, например, тело процедуры (это простейший пример блока). Иногда это тела пакета, хотя чаще под блоком понимают тело процедуры. Будем считать, что у нас есть процедура МAIN, которая вызвала процедуру Р1, которая вызвала процедуру Р32, которая вызвала процедуру Р3.

МAIN Р1 Р2 Р3

Совершенно не важно, как эти процедуры расположены друг относительно друга, то ли они имеют вложенную структуру, то ли расположены в рядок, это совершенно не важно. Считается, что блок в котором произошла ошибка – это аварийный блок, и поэтому он завершается аварийным образом. Если в Р3 у нас произошла ошибка, то Р3 заканчивается аварийно, исключение распространяется на Р2, поскольку Р3 была вызвана из Р2. Если в Р2 не нашлось обработчика, то Р2 то же считается аварийным и распространение идет дольше вплоть до МAIN, если и там нет обработчика, то МAIN считается аварийным. Если в блоке произошла ошибка, то в него управление уже не войдет. Компилятор языка Ада смотрит за тем, чтобы после raise не было больше операторов, так как все равно до них никогда не дойдет управление. Понятно почему все эти raise заключены в условные операторы.

Соседние файлы в папке Лекции по программированию на ЯВУ