Обработка структурированных исключений в C++

Основное различие между обработкой структурированных исключений C (SEH) и обработкой исключений C++ заключается в том, что модель обработки исключений C++ относится к типам, а модель обработки структурированных исключений C имеет дело с исключениями одного типа; в частности, unsigned int. То есть исключения C определяются значением целого числа без знака, а исключения C++ определяются типом данных. При возникновении структурированного исключения в C каждый возможный обработчик выполняет фильтр, который проверяет контекст исключения C и определяет, следует ли принимать исключение, передавать его другому обработчику или игнорировать его. При возникновении исключения в языке C++ оно может быть любого типа.

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

При использовании параметра компилятора /EHsc или /EHsc обработчики исключений C++ не обрабатывают структурированные исключения. Эти исключения обрабатываются только __except структурированными обработчиками исключений или __finally структурированными обработчиками завершения. Дополнительные сведения см. в разделе "Структурированная обработка исключений" (C/C++).

В параметре компилятора /EHa, если исключение C вызывается в программе C++, он может обрабатываться структурированным обработчиком исключений со связанным фильтром или обработчиком C++catch, независимо от того, что динамически ближе к контексту исключения. Например, в этом примере программы C++ возникает исключение C в контексте C++ try :

Пример. Перехват исключения C в блоке перехвата C++

// exceptions_Exception_Handling_Differences.cpp
// compile with: /EHa
#include <iostream>

using namespace std;
void SEHFunc( void );

int main() {
   try {
      SEHFunc();
   }
   catch( ... ) {
      cout << "Caught a C exception."<< endl;
   }
}

void SEHFunc() {
   __try {
      int x, y = 0;
      x = 5 / y;
   }
   __finally {
      cout << "In finally." << endl;
   }
}
In finally.
Caught a C exception.

Классы оболочки исключений C

В простом примере, как показано выше, исключение C может быть поймано только обработчиком многоточия (...catch). Обработчику не передается никакая информация о типе или характере исключения. Хотя этот метод работает, в некоторых случаях может потребоваться определить преобразование между двумя моделями обработки исключений, чтобы каждое исключение C связано с определенным классом. Чтобы преобразовать его, можно определить класс исключения C "оболочка", который можно использовать или производный от этого, чтобы атрибутировать определенный тип класса исключению C. Таким образом, каждое исключение C можно обрабатывать отдельно определенным обработчиком C++ catch , а не всеми из них в одном обработчике.

Класс-оболочка может иметь интерфейс, состоящий из некоторых функций-членов, которые определяют значение исключения; этот интерфейс может получать расширенные сведения о контексте исключения, предоставляемые моделью исключений языка C. Также может потребоваться определить конструктор по умолчанию и конструктор, который принимает unsigned int аргумент (для предоставления базового представления исключений C) и побитового конструктора копирования. Ниже приведена возможная реализация класса оболочки исключений C:

// exceptions_Exception_Handling_Differences2.cpp
// compile with: /c
class SE_Exception {
private:
   SE_Exception() {}
   SE_Exception( SE_Exception& ) {}
   unsigned int nSE;
public:
   SE_Exception( unsigned int n ) : nSE( n ) {}
   ~SE_Exception() {}
   unsigned int getSeNumber() {
      return nSE;
   }
};

Чтобы использовать этот класс, установите пользовательскую функцию преобразования исключений C, вызываемую внутренним механизмом обработки исключений при каждом возникновении исключения C. В функции перевода можно вызвать любое типизированное исключение (возможно SE_Exception , тип или тип класса, производный от SE_Exception), который можно поймать соответствующим обработчиком C++ catch . Вместо этого функция перевода может возвращать, указывая, что она не обрабатывала исключение. Если функция перевода вызывает исключение C, вызывается завершение .

Чтобы указать пользовательскую функцию перевода, вызовите функцию _set_se_translator с именем функции перевода в качестве одного аргумента. Функция перевода, которую вы пишете, вызывается один раз для каждого вызова функции в стеке с try блоками. Функция перевода по умолчанию отсутствует; Если вы не указываете его путем вызова _set_se_translator, исключение C может быть поймано только обработчиком многоточия catch .

Пример. Использование пользовательской функции перевода

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

// exceptions_Exception_Handling_Differences3.cpp
// compile with: /EHa
#include <stdio.h>
#include <eh.h>
#include <windows.h>

class SE_Exception {
private:
   SE_Exception() {}
   unsigned int nSE;
public:
   SE_Exception( SE_Exception& e) : nSE(e.nSE) {}
   SE_Exception(unsigned int n) : nSE(n) {}
   ~SE_Exception() {}
   unsigned int getSeNumber() { return nSE; }
};

void SEFunc() {
    __try {
        int x, y = 0;
        x = 5 / y;
    }
    __finally {
        printf_s( "In finally\n" );
    }
}

void trans_func( unsigned int u, _EXCEPTION_POINTERS* pExp ) {
    printf_s( "In trans_func.\n" );
    throw SE_Exception( u );
}

int main() {
    _set_se_translator( trans_func );
    try {
        SEFunc();
    }
    catch( SE_Exception e ) {
        printf_s( "Caught a __try exception with SE_Exception.\n" );
        printf_s( "nSE = 0x%x\n", e.getSeNumber() );
    }
}
In trans_func.
In finally
Caught a __try exception with SE_Exception.
nSE = 0xc0000094

См. также

Сочетание исключений C (структурировано) и C++