Перехват структурных исключений в С++
Обычно механизм обработки исключений в С++ не позволяет приложению восста новиться после таких серьезных исключений, как нарушение доступа или деление на нуль. Однако Microsoft добавила поддержку соответствующей функциональности в свой компилятор. Так, следующий код предотвратит аварийное завершение процесса.
void main()
{
try
{
* (PBYTE) 0 = 0; // нарушение доступа
}
catch ( ..)
{
// этот код обрабатывает исключения, связанные с нарушением доступа
}
// процесс завершается корректно
}
И это прекрасно, так как приложение может корректно справляться с серьезны ми исключениями. Но было бы еще лучше, если бы блок catch как-то различал коды исключений — чтобы мы могли писать, например, такой исходный код
void Functastic()
{
try
{
* (PBYTE) 0 = 0; // нарушение доступа
int x = 0;
x = 5 / x; // деление на нуль
}
catch (StructuredFxception)
{
switch (StructuredExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
// здесь обрабатывается нарушение доступа
break;
case EXCEPTION_INT_OIVIDE_BY_ZERO:
// здесь обрабатывается деление на нуль
break;
default:
// другие исключения мы не обрабатываем throw;
// может, какой-нибудь другой блок catch
// обработает это исключение
break;
// никогда не выполняется
}
}
}
Так вот, хочу Вас порадовать. В Visual С++ теперь возможно и такое. От Вас потре буется создать С++-класс, используемый специально для идентификации структурных исключений. Например:
#include <eh.h> // для доступа к _set_se_translator
...
class CSE
{
public:
// вызовите эту функцию для каждого потока
static void MapSEtoCE() { _set_se_translator(TranslateSEtoCE); }
operator DWORD() { return(m_er.ExcepUonCude); }
privale:
CSE(PEXCEPTION_POINTERS pep)
{
m_er = *pep->ExceptionRecord;
m_context = *pep->ContextRecord;
}
static void _cdecl TranslateSEtoCE(UINT dwEC, PEXCEPTION_POINTERS pep)
{
throw CSE(pep);
}
private:
EXCEPTION_RECORD m_er;
// машинно-независимая информация ofi исключении
CONTEXT m_context;
// машинно-зависимая информация об исключении
};
Внутри входных функций потоков вызывайте статическую функцию-член Map SEtoCE. В свою очередь она обращается к библиотечной С-функции _set_sefranslator, передавая ей адрес функции TranslateSEtoCE класса CSE. Вызов _set_se_translator сооб щает С++, что при возбуждении структурных исключений Вы хотите вызывать Trans lateSEtoCE. Эта функция вызывает конструктор CSE-объектя и инициализирует два элемента данных машинно-зависимой и машинно-независимой информацией об исключении. Созданный таким образом CSE-объскт может быть вытолкнут ак же, как и любая другая переменная. И теперь Ваш С++-код способен обрабатывать структур ные исключения, захватывая (catching) переменную этого типа.
Вот пример захвата такого С++-объекта.
void Functastic()
{
CSE::MapSEtoCE(); // должна быть вызвана до возникновения исключений
try
{
* (PBYTE) 0 = 0; // нарушение доступа
int x = 0;
x = 5 / x; // деление на нуль
}
catch (CSE se)
{
switch (se)
{
// вызывает функцию-член оператора DWORD()
case EXCEPTION_ACCESS_VIOLATION
// здесь обрабатывается исключение вызванное нарушением доступа
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO
// здесь обрабатывается исключение, вызванное делением на нуль
break;
default:
// другие исключения мы не обрабатываем throw;
// может, какой-нибудь другой блок catch
// обработает это исключение
break;
// никогда не выполняется
}
}
}