Conceitos básicos em usando gerenciado exceções
Este tópico discute a manipulação de exceção nos aplicativos gerenciados. Isto é, um aplicativo que foi criado com a opção do compilador de /clr .
Neste tópico
Lançando exceções em /clr
Blocos try/catch para extensões de CLR
Comentários
Se você compila com a opção de /clr , você pode tratar exceções de CLR bem como Manipulação de exceção C++ padrão e manipulação de exceção estruturado (ELA). Uma exceção de CLR é qualquer exceção gerada por um tipo gerenciado. A classe de System::Exception fornece vários métodos úteis para processar exceções de CLR e é recomendada por uma classe base para classes definidos pelo usuário da exceção.
Capturar os tipos de exceção derivados de uma interface não tem suporte em /clr. Além disso, Common Language Runtime não permite capturar exceções de estouro de pilhas; uma exceção de estouro de pilha encerrará o processo.
Para obter mais informações sobre as diferenças na manipulação de exceção em aplicativos gerenciados e não gerenciados, consulte Diferenças no comportamento de manipulação de exceção em extensões gerenciadas para C++.
Lançando exceções em /clr
A expressão do lançamento do C++ é estendida para gerar um identificador para um tipo CLR. O exemplo a seguir cria um tipo de exceção personalizada e lançará em uma instância desse tipo:
// clr_exception_handling.cpp
// compile with: /clr /c
ref struct MyStruct: public System::Exception {
public:
int i;
};
void GlobalFunction() {
MyStruct^ pMyStruct = gcnew MyStruct;
throw pMyStruct;
}
Um tipo de valor deve ser encaixotado antes de ser gerado:
// clr_exception_handling_2.cpp
// compile with: /clr /c
value struct MyValueStruct {
int i;
};
void GlobalFunction() {
MyValueStruct v = {11};
throw (MyValueStruct ^)v;
}
Blocos try/catch para extensões de CLR
A mesma estrutura try/bloco decatch pode ser usado para capturar exceções e CLR nativos:
// clr_exception_handling_3.cpp
// compile with: /clr
using namespace System;
ref struct MyStruct : public Exception {
public:
int i;
};
struct CMyClass {
public:
double d;
};
void GlobalFunction() {
MyStruct^ pMyStruct = gcnew MyStruct;
pMyStruct->i = 11;
throw pMyStruct;
}
void GlobalFunction2() {
CMyClass c = {2.0};
throw c;
}
int main() {
for ( int i = 1; i >= 0; --i ) {
try {
if ( i == 1 )
GlobalFunction2();
if ( i == 0 )
GlobalFunction();
}
catch ( CMyClass& catchC ) {
Console::WriteLine( "In 'catch(CMyClass& catchC)'" );
Console::WriteLine( catchC.d );
}
catch ( MyStruct^ catchException ) {
Console::WriteLine( "In 'catch(MyStruct^ catchException)'" );
Console::WriteLine( catchException->i );
}
}
}
Saída
In 'catch(CMyClass& catchC)'
2
In 'catch(MyStruct^ catchException)'
11
Ordem de desenrolamento para objetos C++
Desenrolar ocorre para todos os objetos C++ com destruidores que podem estar na pilha de tempo de execução entre a função de reprodução e a função de tratamento. Como os tipos CLR são atribuídos no heap, desenrolando não se aplicam a eles.
A ordem de eventos para uma exceção gerada é a seguinte:
O tempo de execução mostra a pilha que procura a cláusula adequada de captura ou, no caso de ELA, exceto o filtro para ELA, para capturar a exceção. As cláusulas de captura são pesquisadas primeiro na ordem léxica, e depois dinamicamente abaixo da pilha de chamadas.
Uma vez que o manipulador correto está localizado, a pilha é distribuída depois a aquele ponto. Para cada chamada de função na pilha, seus objetos locais destructed os blocos e são executados __finally, da mais aninhado out.
A pilha é distribuída depois uma vez, a cláusula de captura é executada.
Capturando tipos não gerenciado
Quando um tipo de objeto não gerenciado é gerado, está envolvido com uma exceção do tipo System::Runtime.InteropServices::SEHException. Ao procurar pela cláusula adequada de catch , há duas possibilidades.
Se um tipo de C++ nativo está localizado, a exceção será desempacotada e comparada ao tipo localizado. Essa comparação permite que um tipo de C++ nativo é capturado de maneira normal.
Porém, se uma cláusula de catch do tipo SEHException ou qualquer uma de suas classes base é verificada primeiro, a cláusula interceptará a exceção. Em virtude disso, você deve colocar as cláusulas de captura que capturam tipos de C++ nativo antes das cláusulas de captura de tipos CLR.
Observe que
catch(Object^)
e
catch(...)
ambos capturarão qualquer tipo gerado incluir ELA exceções.
Se um tipo gerenciado não é capturado pela captura Object^ (), não destruirá o objeto lançado.
Ao gerar ou ao capturar exceções não gerenciado, recomendamos que você use a opção do compilador de /EHsc em vez de /EHs ou de /EHa.
Consulte também
Referência
safe_cast (Extensões de Componentes C++)
Tratamento de exceções no Visual C++