Ada (798525), страница 20
Текст из файла (страница 20)
Следует заметить, что вAda95 Numeric_Error переопределена таким образом, что является тем же самым, что иConstraint_Error.procedure Numeric_Demo isX : Integer;Y : Integer;beginX := Integer'Last;Y := X + X;-- вызывает Numeric_Errorend Numeric_Demo;10.1.3 Исключение Program_ErrorИсключение Program_Error возбуждается в следующих случаях:•••при попытке вызова подпрограммы, активизации задачи или конкретизации настройки,если тело соответствующего модуля еще не обработано.если выполнение функции достигло завершающего end так и не встретив инструкциювозврата (return ...)при межзадачном взаимодействии во время выполнения инструкции отбора с ожиданием(select ...), когда все альтернативы закрыты и отсутствует раздел elseКроме того, это исключение может возбуждаться в случае возникновения ошибки элаборации.procedure Program_Demo isZ : Integer;function Y(X : Integer) return Integer isbeginif X < 10 thenreturn X;elsif X < 20 thenreturn Xend if;end Y;-- если мы попали в эту точку, то это значит,-- что return не был выполненbeginZ := Y(30);end Program_Demo;10.1.4 Исключение Storage_ErrorИсключение Storage_Error возбуждается в следующих случаях:•••при попытке размещения динамического объекта обнаруживается, что нет достаточногопространства в динамической памяти (куче) которая выделена для задачипри исчерпании памяти выделенной для набора (коллекции) динамически размещаемыхобъектовпри обращении к подпрограмме, когда израсходовано пространство стека10.1.5 Исключение Tasking_ErrorИсключение Tasking_Error возбуждается в случаях межзадачного взаимодействия.
Оно можетбыть возбуждено при возникновении какого-либо исключения внутри задачи которая в текущиймомент времени принимает участие в межзадачном взаимодействии или когда задача пытаетсяорганизовать рандеву с абортированной задачей.10.2 Исключения определяемые пользователемМеханизм исключений Ады был бы не столь полным если бы он позволял использовать толькостандартно предопределенные исключения. Поэтому, в дополнение к стандартнопредопределенным исключениям, Ада дает программисту возможность описывать своисобственные исключения и, в случае необходимости, выполнять их возбуждение.10.2.1 Описание исключения пользователяОписания пользовательских исключений должны размещаться в декларативной части кода, тоесть там где обычно размещаются описания (например, в спецификации пакета).
Формаописания исключений достаточно тривиальна и имеет следующий вид:My_Very_Own_Exception : exception;Another_Exception: exception;10.2.2 Возбуждение исключенийУказание возбуждения исключения достаточно простое. Для этого используется инструкцияraise. Например:raise Numeric_Error;Сгенерированное таким образом исключение не будет ничем отличаться от "истинного"исключения Numeric_Error.10.3 Обработка исключенийВ настоящий момент мы уже знаем стандартно предопределенные исключения Ады, знаем какописывать исключения и знаем как их возбуждать (и свои, и предопределенные). Однако, веськод примеров, которые мы рассматривали, не выполнял никакой обработки исключений.
Во всехрассмотренных случаях, после возникновения исключения, происходило простое завершениевыполнения программы кодом библиотеки времени выполнения Ады. Таким образом, для того,чтобы извлечь некоторую пользу из механизма исключений, необходимо знать каканализировать ситуацию в случае возникновения исключения. Проще говоря - необходиморассмотреть как и где писать обработчики исключений.10.3.1 Обработчики исключенийОбработчик исключения может размещаться в конце тела подпрограммы, пакета илинастраиваемого модуля, в конце тела задачи или входа, а также в конце инструкции блока илиинструкции принятия (accept).
Заметим, что обработчик исключения не является обязательнойчастью этих конструкций.Рассмотрим следующий пример:declareX : Integer range 1..20;beginPut("please enter a number ");Get(X);Put("thank you");exceptionwhen Constraint_Error =>Put("that number should be between 1 and 20");when others =>Put("some other error occurred");end;Здесь описаны два обработчика. В одном выполняется обработка только исключенийограничения (Constraint_Error).
Второй обработчик выполняет обработку всех остальныхисключений (others). Таким образом, если пользователь вводит число в диапазоне от 1 до 20,то ошибки не происходит и появляется сообщение "thank you". В противном случае, передзавершением выполнения появляется сообщение обработчика исключения Constraint_Error:"that number should be between 1 and 20".
В случае возникновения какого-либодругого исключения появится сообщение от второго обработчика: "some other erroroccurred".Можно описать обработчик исключений так, чтобы он обрабатывал несколько указанныхисключений. Для выполнения этого, исключения должны разделяться символом '|':...exception...when Constraint_Error | Storage_Error =>.
. .Также следует заметить, что обработчик when others всегда должен быть последним в спискеобработчиков исключений.Если мы хотим чтобы пользователь продолжал ввод чисел до тех пор пока не пропадет ошибкаограничения, мы можем переписать предыдущий пример подобным образом:loopdeclare...begin...Get(X);exit;exceptionwhen Constraint_Error =>Put("that number ...end;...-- здесь будет продолжено выполнение-- после возникновения исключения-- и обработки его обработчикомend loop;Кроме того, этот пример показывает точку в которой будет продолжено выполнение инструкцийпосле возникновения исключения и его обработки обработчиком.10.3.2 Распространение исключенийДля того, чтобы точно знать в каком месте должен быть расположен соответствующийобработчик исключения, необходимо понимать как при возникновении исключения, во времяработы программы, происходит поиск обработчика.
Этот процесс поиска называетсяраспространением исключений.Если исключение не обрабатывается в подпрограмме в которой это исключение возникло, то онораспространяется в подпрограмму которая вызвала текущую подпрорамму (на уровень выше).После чего, обработчик исключения ищется в вызвавшей подпрограмме. Если обработчикисключения не найден, то исключение распространяется дальше (еще на уровень выше). Этопродолжается до тех пор пока не будет найден обработчик возникшего исключения или не будетдостигнут уровень выполнения текущей задачи (наивысший уровень).
Если в случаедостижения уровня выполнения текущей задачи (то есть наивысшего уровня) обработчикисключения не будет найден, то текущая задача будет аварийно завершена (другими словами,абортирована). Если выполняется только одна задача, то библиотека времени выполнения Адывыполняет обработку возникшего исключения и аварийно завершает выполнение всейпрограммы (другими словами, абортирует выполнение программы).procedure Exception_Demo is--------------------------------procedure Level_2 is-- здесь нет обработчика исключенийbeginraise Constraint_Error;end Level_2;--------------------------------procedure Level_1 isbeginLevel_2;exceptionwhen Constraint_Error =>Put("exception caught in Level_1");end Level_1;beginLevel_1;exceptionwhen Constraint_Error =>Put("exception caught in Exception_Demo");end Exception_Demo;После запуска этой программы будет выдано только сообщение "exception caught inLevel_1".
Следовательно, обработанное исключение не распространяется дальше.Модифицируем процедуру Level_1 поместив инструкцию raise в ее обработчикисключения. Наш предыдущий пример будет иметь следующий вид:procedure Exception_Demo is--------------------------------procedure Level_2 is-- здесь нет обработчика исключенийbeginraise Constraint_Error;end Level_2;---------------------------------procedure Level_1 isbeginLevel_2;exceptionwhen Constraint_Error =>Put("exception caught in Level_1");raise;-- регенерация текущего исключения;-- дает возможность другим подпрограммам-- произвести обработку возникшего-- исключенияend Level_1;beginLevel_1;exceptionwhen Constraint_Error =>Put("exception caught in Exception_Demo");end Exception_Demo;Теперь, инструкция raise, помещенная в обработчик исключения, вызывает распространениеисключения Constraint_Error на один уровень выше, то есть, к вызвавшей подпрограмме.
Такимобразом, исключение может быть получено и соответствующим образом обработано в каждойподпрограмме иерархии вызовов.Инструкцию raise очень удобно использовать в секции others обработчика исключений:...exception...when others =>raise;-- регенерация текущего исключения;-- дает возможность другим подпрограммам-- произвести обработку возникшего-- исключенияend;В этом случае, соответствующее исключение будет продолжать генерироватьсяраспространяться до тех пор, пока не будет обработано надлежащим образом.и10.3.3 Проблемы с областью видимости при обработке исключенийопределяемых пользователемВо всех предыдущих примерах, посвященных обработке исключений, были использованыстандартно определенные исключения Ады.
Обработка исключений определяемыхпользователем идентична обработке предопределенных исключений, однако, при этом могутвозникать некоторые проблемы с областью видимости. Рассмотрим следующий пример:with Ada.Text_IO; use Ada.Text_IO;procedure Demo isprocedure Problem_In_Scope isCant_Be_Seen : exception;beginraise Cant_Be_Seen;end Problem_In_Scope;beginProblem_In_Scope;exceptionwhen Cant_Be_Seen =>Put("just handled an_exception");end Demo;Этот пример не корректен. Проблема в том, что область видимости исключения Cant_Be_Seenограничивается процедурой Problem_In_Scope, которая, собственно и является источникомэтого исключения. То есть, исключение Cant_Be_Seen не видимо и о нем ничего не известноза пределами процедуры Problem_In_Scope.