Tratar exceções estruturadas no C++
A principal diferença entre o tratamento de exceções estruturado (SEH) C e o tratamento de exceções de C++ é que o modelo do tratamento de exceções de C++ lida com tipos, enquanto o modelo de tratamento de exceções estruturado do C lida exceções de um tipo — especificamente, unsigned int
. Ou seja, as exceções C são identificadas por um valor inteiro não assinado, enquanto as exceções C++ são identificadas por tipo de dados. Quando uma exceção estruturada é gerada em C, cada manipulador possível executa um filtro que examina o contexto da exceção de C e determine se aceitará a exceção, a transmitirá para algum outro manipulador, ou a ignorará. Quando uma exceção é gerada em C++, ela pode ser de qualquer tipo.
Uma segunda diferença é que o modelo de tratamento de exceções estruturado de C é chamado de assíncrono, pois as exceções ocorrem secundariamente ao fluxo de controle normal. O mecanismo de tratamento de exceções de C++ é totalmente síncrono, o que significa que as exceções ocorrem apenas quando são geradas.
Quando você usa a opção do compilador /EHs ou /EHsc, nenhum manipulador de exceção do C++ lida com exceções estruturadas. Essas exceções são tratadas apenas por manipuladores de exceção estruturados __except
ou manipuladores de terminação estruturados __finally
. Para obter informações, confira Tratamento de exceções estruturadas (C/C++).
Na opção de compilador /EHa, se a exceção de C é gerada em um programa C/C++, pode ser tratada por um manipulador de exceções estruturado com o filtro associado ou por um manipulador de catch
C++, seja qual estiver dinamicamente mais próximo ao contexto da exceção. Por exemplo, este programa C++ de exemplo gera uma exceção C dentro de um contexto C++ try
:
Exemplo – capturar uma exceção C em um bloco catch do 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.
Classes wrapper de exceção de C
Em um exemplo simples como o acima, a exceção de C pode ser capturada somente por um manipulador de reticências (...) catch
. Nenhuma informação sobre o tipo ou a natureza de exceção é comunicada ao manipulador. Ainda que este método funcione, em alguns casos pode ser aconselhável definir uma transformação entre os dois modelos de tratamento de exceções para que cada exceção de C seja associada a uma classe específica. Para transformar uma, você pode definir a classe da exceção de C como "wrapper", que pode ser usada ou derivada de para atribuir um tipo específico da classe a uma exceção de C. Ao fazer isso, cada exceção C pode ser tratada separadamente por um manipulador C++ catch
específico, em vez de todas em um único manipulador.
Sua classe wrapper pode ter uma interface que consiste em algumas funções de membro que determinam o valor de exceção, e que acessam informações estendidas de contexto de exceção fornecidas pelo modelo da exceção de C. Também pode ser aconselhável definir um construtor padrão e um construtor que aceite um argumento unsigned int
(para fornecer para a representação subjacente da exceção de C) e um construtor de cópia bit a bit. Segue uma possível implementação da classe wrapper de exceção do 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;
}
};
Para usar essa classe, instale uma função personalizada de tradução da exceção de C, chamada pelo mecanismo interno de tratamento de exceções sempre que uma exceção de C é lançada. Dentro de sua função de tradução, você pode gerar qualquer exceção digitada (talvez um tipo SE_Exception
, ou um tipo de classe derivada de SE_Exception
) que possa ser capturada por um manipulador de correspondência C++ catch
adequado. A função de tradução pode, em vez disso, retornar, o que indica que ela não conseguiu tratar a exceção. Se a própria função de tradução criar uma exceção de C, terminate é chamado.
Para especificar uma função personalizada de tradução, chame a função _set_se_translator com o nome da função de tradução como seu único argumento. A função de tradução que você grava é chamada uma vez para cada invocação de função na pilha que tem blocos try
. Não há nenhuma função padrão de tradução; se você não especificar uma chamando _set_se_translator, a exceção de C só pode ser capturada por um manipulador de reticências catch
.
Exemplo – Usar uma função de tradução personalizada
Por exemplo, o código a seguir instala uma função personalizada de tradução e gerará a exceção de C que é envolvida pela classe 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
Confira também
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de