Обработка исключительных ситуаций (ИС)

Исключительные ситуации могут возникать в связи с различного рода ошибками выполнения программы, действиями пользователя или непредвиденными ситуациями.

Примеры:

1. деление на ноль.

2. не выделена динамическая память оператором NEW.

3. пользователь нажал клавиши [Ctrk+C], [Ctrl+Break].

4. попытка открыть несуществующий файл.

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

В зависимости от инструментальные среды реализации версии языка С++, отличаются и средства обработки исключительных ситуаций. Но на сегодняшний момент именно файловые системы типа Builder C++ являются предоставляют наиболее развитые инструменты обработки исключительных ситуаций.

По умолчанию, в интегрированной системе визуального программирования IDE - Builder C++ исключительная ситуация характеризуется созданием временного объекта специального вида, так называемого исключения. Объект исключения разрушается автоматически после обработки. Если это исключение специально не перехватить, то оно будет обработано стандартным образом методом:

Application -> HandleException

Как правило, на экране появляется диалоговое окно с сообщением следующего вида:

 
 


Имя приложения


Division by zero

ОК

- Деление на ноль

Очевидно, что в С-программе целесообразно предусмотреть собственный перехват и обработку исключений с целью:

1) Избежать снятия выполнения программы из-за «мелочей».

2) Предотвратить «утечку» ресурсов в виде:

· потери динамически распределенной памяти.

· незакрытых файлов.

· не уничтожения временных файлов и прочего «мусора».

3) Точно установить причину исключения и сообщить об этом пользователю и разработчику для устранения.

4) Обеспечить «мягкое» завершение программы.

Первый способ обработки исключительных ситуаций основан на использовании блока операторов

Try

{ // Операторы, способные к ИС. }

_Finally

{ // Безусловно, выполняемые операторы. }

Пример попытки открытия файла на ввод и запись в него последовательности символов «пример».

File *fp; - любое имя указывающее на предопределенную структуру через него идет обмен файлами

Int size;

Char *str;

……….

Try

{ Fp=fopen (“a.tmp”, “w”);

Fprintf (fp, “пример”);

Str=new char(size)

_finally

{ Remove (“a.tmp”);

Free (str); }

Недостатки первого способа обработки исключительных ситуаций:

1) Не приняты меры для дальнейшей, нормальной работы программы при генерации исключительной ситуации.

2) Пользователь не информирован о возникновении исключительной ситуации и желательных действиях. Это связано с тем что – _finally не знает, произошло ли исключение и его причину, так как проверка и идентификация исключительной ситуации генерируется функцией ExcepAddr только после выхода из блока операторов _ finally.

Второй способ обработки ИС был введен еще в Turbo C++. Он основан на безусловном завершении приложения вызовом функции формата:

<stdlib.h>

void exit(status);

int

Параметр status определяет код завершения. Если параметр равен 0 – это означает нормальное завершение программы. Если параметр равен 1 – то это означает аварийное завершение.

Функция EXIT прекращает работу программы следующим образом:

- закрывает все открытые файлы,

- очищает буфера обмена ввода-вывода, распечатывая из них информацию,

- последовательно (в обратном порядке) и безусловно выполняет собственные пользовательские функции завершения, которые имеют:

<stdlib.h>

int atexit (имя функции);

void *func

Пример.

atexit (myexit1);

atexit(myexit2);

void myexit1(void) // удаление всех *.tmp в текущем каталоге.

{ struct ffblk My_ ffblk; // требуется подключение файлов <dos.h>, <dir.h>

int D;

D=findfirst(“*.tmp”,&ffblk,0); // ffblk – системная структура, содержащая описание одного файла

while(!D)

{ Remove (My_ ffblk.ff_name); // системная функция удаления файла

D=findnext(&ffblk); // системная функция перехода к чтению атрибутов очередного файла

}

}

Второй способ позволяет, таким образом, предусмотреть мягкую обработку исключительной ситуации, ее проанализировать и главное его достоинство, что он действует во время выполнения всей программы.

Третий способ (кардинальный, в интегрированный системе визуального программирования Builder C++) основан на обработке классов исключительных ситуаций. Иерархия классов исключительных ситуаций VCL поддерживается автоматически подключаемой библиотекой <vcl.h> (ко всем модулям).

EMATH ERROR – базовый класс ИС с операциями с плавающей запятой

EOVERFLOW – переполнение регистра

EZERODIVIDE – деление на ноль

 
 


EUNDERFLOW – потеря значащих разрядов

EXCEPTION – базовый класс VCL

 
 


ECONTROLC – пользователь нажал [CTRL+C]

EABORT – намеренное прерывание вычислений

E STREAM ERROR – базовый класс исключений ошибок потоков

 
 


EFOPEN ERROR – ошибка открытия файла

EF CREAT ERROR -...

Использование блока операторов:

Try

{ …}

Catch (Тип ИС)

{ …}

позволяет организовать обработку конкретной исключительной ситуации. Причем количество используемых операторов catch не ограничено. Исключительная ситуация в операторе catch может быть установлена:

- ссылкой на класс исключения операций библиотеки <vcl.h>,

- специально генерируем исключением:

catch(std::bad_alloc) // недостаток памяти при использовании оператора NEW,

- многоточием (…) для обработки любой ИС.

В отличие от _finally, блоки catch позволяют установить тип сгенерированной ИС и дифференцированно на них реагировать. Допускает несколько блоков catch в одном try.

Пример.

Пусть в интегрированный системе визуального программирования Builder C++ в двух окнах редактирования Edit1 и Edit2 пользователь должен ввести действительные числа c типом данных float.

Float A;

Try

{ A=StrToFloat(Edit1-> Text); // переводит символьную строку в тип данных float

A=A / StrToFloat (Edit2 -Text); }

Catch(Econvert Error &)

{ Application -> MessageBox(“Ввели ошибочное число”, “Повторите ввод”, MВ_ОК);

/ /Слишком большое число }

Catch(EZeroDivide &) – ошибка совершена

{ Application -> MessageBox(“Ввели ноль”, “Повторите ввод”, MВ_ОК); }

Так как исключения VCL имеют иерархию, то можно обработать сразу совокупность исключений, указав базовый класс:

Catch(EmathError &)

{ Application -> MessageBox (“Ошибка вычислений”, “Повторите ввод”, MВ_ОК); }

Использование символа «…»(многоточия) позволяет перехватить любые исключения, например:

Catch(…)

{ ShowMessage(“Произошла ошибка); }

Блоки try … catch могут быть вложенными явным или неявным образом.

Четвертый способ позволяет обрабатывать ИС на уровне всего приложения. Для этого предусмотрено событие OnException самого приложения Application. Здесь используется класс Exception (он наследует все функции базового класса) для идентификации ИС отличным от библиотеки VCL.h способом.

Для использования класса установки исключительной ситуации Exception и события ОnException надо сделать следующее:

а) в заголовочный файл приложения добавить объявления собственного обработчика ИС, например MyIS:

Void_fastcall MyIS(Tobject*Sender,Exception*E)

в) в файле unit- модуля реализовать обработчики, например для первой формы TForm1 проекта в интегрированный системе визуального программирования Builder C++:

Void_fastcall TForm1::MyIS(Tobject*Sender,Exception*E)

{ … }

с) указать приложению, что событие OnException будет обрабатываться не системно, а с помощью собственной функции, например следующим образом:

Application -> OnException = MyIS;

Этот обработчик будет обрабатывать только те исключительные ситуации, которые ранее не были перехвачены другим способом.

Void _fastcаll TАorm1::MyIS(Tobject *Sender, Exception *E)

{ AnsiString S=”Ошибка “;

If (string(E -> СlassName()) = = “EZeroDivide”)

S+= “Деление на ноль”;

If (string(E -> СlassName()) = = “EOverFlow”)

S+= “Переполнение”;

Application -> MessageBox(S.C_str(), “Повторите ввод”, MВ_ОК); // Вывод диалогового окна с сообщением

}

Пятый способ основан на обработке сигналов был также как и второй введен еще в Turbo C++. В языке С++ сигнал представляет собой непредвиденное событие, которое может вызвать прерывание программы. Для этого используется библиотечный файл < Signal.h >.

Основные стандартные сигналы:

· SIGINT – получение программой интерактивного сигнала, например нажатие пользователем комбинации клавиш [Ctrl+C] для снятия программы с выполнения.

· SIGUSR1, SIGUSR2,… - сигналы специально генерируемые функцией Raise(), в которую передаются целочисленные номера сигнала.

· SIGFPE – возникновение арифметические ошибки.

· SIGABRT – аварийное завершение программы, например по требованию операционной системы.

Технология организации обработки ИС на основе сигналов следующая:

а) Вызов обработчика должен быть заранее включен. Например, при открытии формы, то есть событии OnCreat, надо установить этот обработчик с помощью оператора:

Signal(сигнал, имя функции);

Например, Signal(SIGINT, MyIS);

в) Написать встроенный модуль в виде функцию обработки исключительной ситуации как сигнала:

#include <signal.h>

void MyIS(int N)

{ if (MessageDlg(“Продолжать?”,mbConfirmation, TMsgDlgButtons()<<mbYes<<mbNo, 0)= = mrYes)

signal({SIGINT, MyIS); // Повторная установка обработчика

else

exit(0);

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: