C++ Программирование в среде С++ Builder 5

Процессорные исключения


Наибольший интерес для нас представляют исключения, связанные с процессором. Их, как уже говорилось, нельзя обрабатывать стандартными средствами C++. Для этих исключений в заголовке winbase.h определен ряд символических констант. Вот некоторые из них:

EXCEPTION_ACCESS_VIOLATION

EXCEPTION_ARRAY_BOUNDS_EXCEEDED

EXCEPTION_FLT_DENORMAL_OPERAND

EXCEPTION_FLT_DIVIDE_BY_ZERO

EXCEPTION_FLT_INEXACT_RESULT

EXCEPTION_FLT_INVALID_OPERATION

EXCEPTION_FLT_OVERFLOW

EXCEPTION_FLT_STACK_CHECK

EXCEPTION_FLT_UNDERFLOW

EXCEPTION_INT_DIVIDE_BY_ZERO

EXCEPTION_INT_OVERFLOW

EXCEPTION_PRIV_INSTRUCTION



EXCEPT ION_IN_PAGE_ERROR

EXCEPTION_ILLEGAL_INSTRUCTION

EXCEPTION_NONCONTINUABLE_EXCEPTION

EXCEPTION_STACK_OVERFLOW

EXCEPTION_INVALID_DISPOSITION

EXCEPTION_GUARD_PAGE

Ниже показан пример, в котором имитируется нарушение доступа путем разыменования нулевого указателя. Функция фильтра детектирует эту ошибку, и обработчик исключения выводит соответствующее собщение:

///////////////////////////////////////////////////

// Access.cpp: Применение SEH для перехвата

// системных исключений.

//

#include <except.h>

#include <iostream.h>

#pragma hdrstop

#include <condefs.h>

static int xfilter(EXCEPTION_POINTERS *info)

{

if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)

return EXCEPTION_EXECUTE_HANDLER;

else

return EXCEPTION_CONTINUE_SEARCH;

}

int main () {

try (

int *p = NULL;

*P = -1;

}

_except(xfilter(GetExceptionInformation())) { cerr << "Exception Access Violaton caught..." << endl;

exit(l);

} cout<<"Normal exit..." << endl;

return 0;

}

Для справки приведем описание структуры exception_pointers:

struct EXCEPTION_POINTERS {

EXCEPTION_RECORD *ExceptionRecord;

CONTEXT *Context;

};

Struct EXCEPTION_RECORD { DWORD ExceptionCode;

DWORD ExceptionFlags;

struct EXCEPTION_RECORD *ExceptionRecord;

void *ExceptionAddress;

DWORD NumberParameters;

DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];


Как уже говорилось, структуры управления исключениями SEH и C++ могут быть вложены друг в друга. Более того, except-обработчик может выбрасывать исключение C++, которое будет далее перехватываться catch-обработчиком. Можно в целях удобства и единообразия заключить все критические участки кода, могущие возбудить процессорные исключения (или вообще всю программу) в блоки try/ except, выбрасывающие исключения C++, и затем обрабатывать их наравне с другими исключениями. Рассмотрите такой пример:

////////////////////////////////////////////////

// SehPlus.cpp: Переход от SEH к C++.

//

#include <iostream.h>

#include <excpt.h>

#include <stdexcept>

#pragma hdrstop

#include <condefs.h>

static EXCEPTIONJRECORD eRec;

static int xfliter(EXCEPTION_POINTERS *xp) {

eRec = *(xp->ExceptionRecord);

return EXCEPTION_EXECUTE_HANDLER;

}

int main () {

double d = 10000;

try { try {

for (int i=5; i>=0; i-) { d = d / i;

cout << i << "... ";

} }

_except- ixfliter(GetExceptionInformation ())) ( if (eRec.ExceptionCode ==

EXCEPTIOM_FLT_DIVIDE_BY_ZERO) throw runtime error(

"Floating point divide by zero!");

else

throw runtime_error(

"Unknown processor exception.");

} }

catch(const exception &e) { cout << e.what() << end1;

} return 0;

}

Программа выводит:

5... 4... 3...2... I... Floating point divide by zero!



Целесообразно было бы предусмотреть для процессорных исключений специальный класс, производный от, например, runtime_error, дополнив его структурой EXCEPTION RECORD. Тогда вообще вся обработка осуществлялась бы средствами C++.



Заключение



В этой главе вы познакомились со средствами C++, позволяющими сделать обработку ошибок и других исключительных ситуаций гораздо более единообразной и надежной, чем это было возможно когда-либо прежде. Кроме того, исключения используются стандартными библиотеками и в самом языке (класс string, операция new). Поэтому я всячески призываю вас практиковаться и привыкать к управлению исключениями.


Содержание раздела