Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Пример работы с... 65535
Содержание сайт... 65535
ТЕХНОЛОГИИ ДОСТ... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Создание отчето... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Модуль Forms 65535
Имитационное мо... 60345
Реклама
Сейчас на сайте
Гостей: 5
На сайте нет зарегистрированных пользователей

Пользователей: 13,115
новичок: sborzabor
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

База данных склада на Delphi + Схема БД
Сравнение двух бинарных деревьев на Turbo Pascal + отчет
Моделирование процесса обработки заданий пакетным режимом работы с квант...

Реклама



Подписывайся на YouTube канал о программировании, что бы не пропустить новые видео!

ПОДПИСЫВАЙСЯ на канал о программировании
Исключительные ситуации
При работе программы могут возникать различного рода ошибки: переполнение, деление на нуль, попытка открыть несуществующий файл и т.п. При возникновении таких исключительных ситуаций программа генерирует прерывание, называемое исключением. В результате выполнение дальнейших вычислений прекращается. Исключение — это объект специального вида, характеризующий возникшую в программе особую ситуацию. Он может также содержать в виде параметров некоторую уточняющую информацию. Особенностью исключений является то, что это сугубо временные объекты. Как только они обработаны каким-то обработчиком, они разрушаются.
Если исключение не перехвачено нигде в программе, то оно автоматически обрабатывается методом TApplication.HandleException. Он обеспечивает стандартную реакцию программы на большинство исключений — выдачу пользователю краткой информации в окне сообщений и уничтожение экземпляра исключения. На рис. 3 приведен пример такого стандартного сообщения для случая целочисленного деления на нуль.
целочисленное деления на нуль
Рис. 3
Если работа по отладке программы ведется в среде Delphi, то при исключениях, подобных указанному на рис. 3, могут появляться сообщения отладчика Delphi, вид которых приведен на рис.4.
Сообщения исключительных ситуаций
Рис. 4
При этом на экране открывается окно Редактора Кода на строке, при выполнении которой произошло исключение. Необходимо щелкнуть на ОК, а затем следует просмотреть переменные и выяснить причину исключения. После этого возможны следующие действия:
1) нажатие — прекращение выполнения приложения;
2) нажатие или выполнение команды Run | Run — продолжение работы приложения;
3) нажатие или — продолжение отладки по шагам.
При необходимости можно отключить появление сообщений отладчика. Для этого надо выполнить команду Tools | Debugger Options, в открывшемся диалоговом окне выбрать страницу Language Exceptions и на ней выключить опцию Stop On Delphi Exceptions.
Если не принять соответствующих мер в случае генерации исключений, то к неприятностям прекращения вычислений могут добавиться еще неприятности, связанные с так называемой утечкой ресурсов. Под этим подразумеваются потери динамически распределяемой памяти, незакрытые файлы, не уничтоженные временные файлы на диске и прочий информационный «мусор». Например, пусть выполняется некоторая программа, в которой имеются следующие операторы:
AssignFile(F,'a.tmp');
Rewrite (F);
New(P);

Erase(F);
Dispose (P);



В программе открывается временный файл с именем a.tmp, чтобы хранить в нем результаты промежуточных вычислений. В конце программы файл должен быть уничтожен процедурой Erase. Кроме того, процедурой New динамически выделяется некоторый объем оперативной памяти. Память будет освобождаться после ее использования процедурой Dispose. Если в промежуточных операторах, помеченных выше точками, возникнет исключение, то вычисления прервутся и процедуры Erase и Dispose не будут выполнены. В результате память, выделенная процедурой New, останется недоступной, а на диске сохранится временный и уже ненужный файл a.tmp.
Избежать подобного рода неприятностей можно несколькими путями:
1. Не допускать исключений, производя предварительную проверку каждой операции, способной привести к исключительным ситуациям.
2. Защищать код очистки информационного «мусора» с помощью программного блока try ... finally.
3. Обрабатывать исключения в блоках try ... except.
Первый из указанных путей борьбы с исключениями предусматривает введение проверки перед выполнением каждой операции, способной привести к исключительным ситуациям. Например, перед делением двух переменных А и В, из которых вторая может оказаться нулем, надо проверить значение В оператором
if ( В = 0 ) then ...



и выполнить необходимые действия, если переменная В окажется равной нулю. Аналогично можно проверять возможность переполнения при делении, умножении и других арифметических операциях, проверять наличие достаточного места в динамически распределяемой памяти при выделении новой области или создании нового объекта, проверять ошибки файлового ввода вывода и т. д. При использовании библиотечных функций можно перед каждым обращением к функции или процедуре производить проверку допустимости всех ее аргументов.
Достоинством рассмотренного подхода к устранению исключений является почти «бессбойная» работа программы (если, конечно, действительно проверяется каждая операция). Слово «бессбойная» здесь недаром поставлено в кавычки. Сложные программы, увы, всегда могут содержать ошибки и возможности сбоя. Даже тщательная предварительная проверка всех операций не способна это устранить.
При несомненных достоинствах рассмотренного подхода у него есть ряд недостатков. Основной из них — увеличение размера программы (особенно, если она проводит много сложных вычислений) за счет многочисленных операторов проверки и замедление ее работы. К тому же при использовании библиотечных функций и процедур, реализация которых неизвестна, не всегда можно быть уверенным, что проверки гарантируют их бессбойную работу.
В настоящее время проверку отдельных операций и функций на возможность появления исключительных ситуаций надо признать устаревшим подходом, приводящим к неоправданному усложнению программы и снижению ее эффективности. Современный подход заключается в обработке исключений.
Программист должен принять все мыслимые меры, чтобы ни при каких ошибках пользователя и ни при каких сочетаниях данных приложение не заканчивалось бы аварийно. Но если все-таки аварийное завершение происходит, необходима полная очистка «мусора» — удаление временных файлов, освобождение памяти, разрыв связей с базами данных и т. д.
Второй способ борьбы с исключениями состоит в использовании программного блока try ... finally. Блок, содержащий совокупность операторов, способных привести к исключению, можно оформить следующим образом:
try
<операторы, способные привести к исключению и к появлению "мусора">
finally
<операторы, выполняемые в любом случае и производящие зачистку "мусора">
end;



В этом случае операторы в разделе finally будут выполняться всегда, независимо от того, было или не было исключение. После выполнения этих операторов вычисления, как и ранее, прерываются. Если в блоке try были открыты какие-то временные файлы, динамически выделялась память под временные объекты, выполнялись соединения с какими-то базами данных, а после всего этого произошла ошибка, вызвавшая исключение, то в блоке finally можно убрать весь «мусор»: удалить ненужные временные файлы, освободить память от временных объектов, разорвать связь с базой данных.
К сожалению, остаются другие из рассмотренных проблем: необходимость принять какие-то меры для дальнейшей нормальной работы программы при генерации исключения, а также необходимость уведомить пользователя о желательных действиях с его стороны. Решить эти проблемы в данном случае невозможно, поскольку при выполнении операторов раздела finally программа не знает, произошло ли исключение и если произошло, то какое именно.
Рассмотренный способ использования блока try ... finally позволяет защитить ресурсы программы внутри блока. Существует также способ глобального выделения и инициализации ресурсов, с защищенной их очисткой. Он состоит в использовании двух специальных включаемых в модуль разделов initialization и finalization. Раздел initialization, выполняемый один раз при первом упоминании в программе данного модуля, можно использовать для однократного выделения необходимых глобальных ресурсов. А раздел finalization, гарантированно выполняемый в конце работы программы независимо от наличия или отсутствия исключений, можно использовать для очистки этих и других ресурсов, затребованных при работе программы. Например, если в процессе работы программы временные файлы с расширениями .tmp могут создаваться в каталоге, имя которого записано в переменной sdirtmp, то гарантированно удалить их при завершении работы программы можно следующими операторами:
var
sSR:TSearchRec; F:File;
ires:integer;
….
initialization
….
finalization
ires := FindFirst(sdirtmp+'*.tmp', faAnyFile, sSR);
while ires=0 do
begin
AssignFile(F, sdirtmp+sSR.name);
Erase(F);
ires := FindNext(sSR)
end;

end.




В этом фрагменте программы с помощью процедуры Erase из каталога, имя которого записано в переменной sdirtmp, удаляются все файлы с расширением .tmp. Поиск этих файлов осуществляется функциями FindFirst и FindNext.
В разделе finalization можно определить, завершается ли программа нормально или в результате генерации исключения, проверив функцию ExceptAddr.
Следует учесть, что включение в модуль раздела finalization возможно только при наличии в нем раздела initialization. Даже если он не требуется, нужно включить в программу хотя бы пустой раздел initialization, если предполагается использовать очистку ресурсов в разделе finalization.
Наиболее кардинальным способом борьбы с исключениями является третий из вышеупомянутых - обработка исключений с помощью блоков try ... except. Синтаксис этих блоков следующий:
try
<Исполняемый код>
except
<Код, исполняемый в случае ошибки>;
end;



Операторы раздела except выполняются только в случае генерации исключения в операторах блока try. В результате при возникновении исключения появляется возможность предпринять какие-либо действия: известить пользователя о возникшей проблеме и подсказать ему пути ее решения, принять какие-то меры к исправлению ошибки (например, при делении на нуль заслать в результат очень большое число соответствующего знака) и т.д.
Важным является то, что в разделе except можно определить тип сгенерированного исключения и дифференцированно реагировать на различные исключительные ситуации. Это делается с помощью оператора:
on <класс исключения> do <оператор>;



В языке Object Pascal исключительные ситуации представляют собой объекты, содержащие информацию, идентифицирующую ошибку и место ее возникновения. Внутри раздела except создаются обработчики особых ситуаций для классов исключительных ситуаций. Обработчик особой ситуации имеет следующий формат:
try
<Исполняемый код>
except
on E: ESomeException do <обработчик исключения>;
end;



Для обработки особой ситуации Delphi предоставляет возможность создания временных объектов особой ситуации (Е), которые могут использоваться в обработчике исключения. Временный объект особой ситуации имеет тот же тип, что и объект исключения, который он обозначает (ESomeException).
Существуют предопределенные классы исключительных ситуаций для обработки стандартных ошибок, таких как нехватка памяти, деление на нуль, числовое переполнение, ошибки ввода-вывода и другие. Некоторые из них следующие:
1. EMathError - класс-предок исключений, случающихся при выполнении операций с плавающей точкой;
EInvalidArgument - значение параметра выходит за диапазон значений
EInvalidOp - передача математическому сопроцессору ошибочной конструкции;
EOverflow - переполнение разрядов при работе со слишком большими величинами;
EUnderflow - потеря разрядов при работе со слишком малыми величинами;
EZeroDivide - деление на ноль.
2. EIntError - класс-предок исключений, случающихся при выполнении целочисленных операций;
EDivByZero - деление на ноль;
EIntOverflow - выполнение операций, приводящих к переполнению целых переменных;
ERangeError - значение целочисленного выражения выходит за пределы установленного целочисленного типа. Попытка обращения к элементу массива по индексу, выходящему за пределы массива.
3. EListError - обращение к элементу списка (String, List, TStringList) по индексу, выходящему за пределы допустимых значений.
4. EInOutError - ошибки при операциях с файловой системой. Код ошибки возвращается в локальной переменной ErrorCode, которая может принимать следующие значения:
2 - файл не найден;
3 - неверное имя файла;
4 - слишком много открыто файлов;
5 - отказ в доступе;
100 - конец файла;
101 - диск полон;
106 - неверная операция ввода.



5. EConvertError - ошибки преобразования типов (простых, объектных).
Операторы on...do позволяют проводить выборочную обработку различных исключений. Пример такой обработки:
var A : shortint;

try

С := StrToInt(Editl.text); A := В div С;
except
on EConvertError do
MessageDlg('Вы ввели ошибочное число; повторите ввод', mtWarning, [mbOk], 0);
on EDivByZero do
MessageDlg('Вы ввели нуль; повторите ввод', mtWarning, [mbOk], 0) ;
on EIntOverflow do
if (B*C) >= 0 then A := 32767 else A := -32767;

end;



В этом примере выполняются чтение целого числа, введенного пользователем в окно редактирования Editl, и деление на него переменной В. Если пользователь ввел не целое число (например, по ошибке нажал не цифру, а какой-то буквенный символ), то при выполнении функции StrToInt возникнет исключение класса EConvertError. Соответствующий обработчик исключения сообщает пользователю о сделанной ошибке и советует повторить ввод. Аналогичная реакция следует на ввод пользователем нуля (класс исключения EDivByZero). Если же при делении возникает целочисленное переполнение (класс исключения Elnt-Overflow), то результату присваивается максимальное положительное или отрицательное значение.
Некоторые исключения имеют дополнительные поля (свойства), уточняющие вид ошибки. Например, это относится к исключению файлового ввода/вывода EInOutError, которое имеет свойство errorcode типа integer. Это свойство содержит стандартный для Object Pascal номер ошибки файлового ввода/вывода.
Чтобы воспользоваться полями исключений, оператор on надо записывать в виде
on <имя>: <класс исключения> do
<операторы с конструкциями <имя>.<имя поля>>;



Содержащееся в этом операторе <имя> носит сугубо локальный характер, нигде ранее определяться не должно и вводится только для того, чтобы можно было сослаться на поле по имени объекта исключения.
Пример использования полей при операциях файлового ввода/вывода (подразумевается, что в переменной filename типа string хранится имя обрабатываемого файла):
on IO: EInOutError do
begin
Case IO.errorcode of
2: s:='Файл ''' +s+''' не найден';
3: s:='Ошибочное имя файла ''' + s+ ' ' ' ' ;
4: s:='Слишком много открытых файлов';
5: s:='Файл ''' +s+''' не доступен';
100: s:= 'Достигнут конец файла ''' +s+'’'’;
101: s:= 'Диск переполнен при работе с файлом ''' + s + ' ' ' ' ;
106: s:= 'Ошибка ввода при работе с файлом ' ' ' +s+ ' ' ' ' ;
end;
MessageDlg(s, mtWarning, [mbOk], 0);
end;



Приведенный код анализирует поле исключения и выдает сообщение о виде ошибки.
Помимо операторов on, обрабатывающих заданные типы исключений, в раздел except может быть включен оператор else, в котором выполняется обработка всех не перехваченных ранее исключений, т.е. происходит обработка по умолчанию. Например:
except
on . . . ;
on . . . ;
else <обработчик всех не перехваченных ранее событий>;
end;




Оператор else должен идти последним, так как в противном случае все обработчики, записанные после него, работать не будут, поскольку все исключения уже будут перехвачены. Внутри обработчика по умолчанию можно получить доступ к объекту исключения, воспользовавшись функцией ExceptObject.
В раздел except могут включаться или только операторы on, или только какие-то другие операторы. Смешение операторов on с другими не допускается.
Раздел except может включаться совместно с описанным ранее разделом finally. Например, можно организовать блоки try следующим образом:
try

try

finally

end;
except

end;



Блоки try...except могут быть вложенными явным или неявным образом. Примером неявной вложенности является блок try...except, в котором среди операторов раздела try имеются вызовы функций или процедур, которые имеют свои собственные блоки try...except. Рассмотрим последовательность обработки исключений в этих случаях. При генерации исключения сначала ищется соответствующий ему обработчик on в том блоке try...except, в котором создалась исключительная ситуация. Если соответствующий обработчик не найден, поиск ведется в обрамляющем блоке try...except (при наличии явным образом вложенных блоков) и т.д. Если в данной функции или процедуре обработчик не найден или вообще в ней отсутствуют блоки try...except, то поиск переходит на следующий уровень — в блок, из которого была вызвана данная функция или процедура. Этот поиск продолжается по всем уровням. И только если он закончился безрезультатно, выполняется стандартная обработка исключения, заключающаяся, как уже было сказано, в выдаче пользователю сообщения о типе исключения.
Как только оператор on, соответствующий данному исключению, найден и выполнен, объект исключения разрушается и управление передается оператору, следующему за соответствующим блоком try...except.
Возможен также вариант, когда в самом обработчике исключения в процессе обработки возникла исключительная ситуация. В этом случае обработка прерывается, прежнее исключение разрушается и генерируется новое исключение. Его обработчик ищется в блоке try...except, внешнем по отношению к тому, в котором возникло новое исключение.
Например, для создания устойчивого к ошибкам приложения, записывающего данные в файл, можно использовать следующий код:
begin
assignfile(f, 'data.dan');
try
append(f);
try
writeln (f,s);
finally
closefile(f) ;
end;
except
on E: EInOutError do
if E.ErrorCode = 2 then
if MessageDlg('Файл не найден. Создать его?', mtError, [mbYes, mbNo],0)=mrYes
then FileCreate('data.dan');
end;
end;



В данном примере внутренний блок try … finally используется для того, чтобы файл был закрыт в любом случае, т. е. независимо от того, была ошибка или нет.
Внешний блок try … except используется для обработки исключительной ситуации, которая может произойти в программе. После закрытия файла во внутреннем блоке finally блок except использует временный объект Е для определения типа произошедшей ошибки ввода/вывода.





Опубликовал Kest Декабрь 22 2009 15:10:44 · 0 Комментариев · 12112 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Комментарии
Нет комментариев.
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
DAlarm
MiniChat
PHP: Полезные приемы
DiZsubmit
Советы по Delphi
Gold Submitter II...
PHP5. Профессиона...
SMLPack v1.0
Введение в станда...
EMSQuickImport
Х. М. Дейтел, П. ...
DelphiX
Файловый менеджер
ICQ
Delphi 2005 для W...
isoCanvas (Редакт...
PBFoldder
PCXReader. Програ...
PCX
Drag&Drop

Топ загрузок
Приложение Клие... 100522
Delphi 7 Enterp... 91592
Converter AMR<-... 20101
GPSS World Stud... 15290
Borland C++Buil... 12992
Borland Delphi ... 9103
Turbo Pascal fo... 7111
Калькулятор [Ис... 5180
Visual Studio 2... 5031
FreeSMS v1.3.1 3559
Случайные статьи
объекту
Процедура SetPalet...
Сбрасывание объект...
UNTRACE (ЗАВЕРШИТЬ...
Это предотвратит у...
Установление связе...
РЕЖИМ "КОНСУЛЬТАЦИЯ"
ЭТАП 3. ВЫЯСНЕНИЕ ...
Вывод команды show...
Проверка грамматик...
Рейтинг кредитный
Кэширование узла (...
Удаления ненужных ...
Инвариант на второ...
Формы расширенного...
Языки С и С ++: со...
Предисловие
Функция GetPixel -...
Стек
Школа SEO Россия
Приоритеты и ресурсы
Интернета
Непроверяемые прео...
Снизить шанс досту...
с Windows 2000
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?