Обработка структурированных исключений в 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
См. также
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделе:Отправить и просмотреть отзыв по