Conceitos básicos em usar exceções gerenciadas
Este tópico discute o tratamento de exceções em aplicativos gerenciados. Ou seja, um aplicativo compilado com a opção do compilador /clr.
Neste tópico
Comentários
Se você compilar com a opção /clr, poderá lidar com exceções CLR, bem como a classe padrão Exception fornece muitos métodos úteis para processar exceções CLR e é recomendado como uma classe base para classes de exceção definidas pelo usuário.
Não há suporte para a captura de tipos de exceção derivados de uma interface em /clr. Além disso, o Common Language Runtime não permite fazer catch de exceções de estouro de pilha; uma exceção de estouro de pilha encerrará o processo.
Para obter mais informações sobre diferenças no tratamento de exceções em aplicativos gerenciados e não gerenciados, consulte Diferenças no comportamento de tratamento de exceções em Managed Extensions for C++.
Lançando exceções em /clr
A expressão de lançamento C++ é estendida para lançar um identificador para um tipo CLR. O exemplo a seguir cria um tipo de exceção personalizado e, em seguida, lança 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 boxed antes de ser lançado:
// clr_exception_handling_2.cpp
// compile with: /clr /c
value struct MyValueStruct {
int i;
};
void GlobalFunction() {
MyValueStruct v = {11};
throw (MyValueStruct ^)v;
}
Fazer Try/Catch de blocos para extensões CLR
A mesma estrutura de blocos try
/catch
pode ser usada para capturar CLR e exceções nativas:
// 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++
O desenrolamento ocorre para quaisquer objetos C++ com destruidores que podem estar na pilha de tempo de execução entre a função de lançamento e a função de manipulação. Como os tipos CLR são alocados no heap, o desenrolamento não se aplica a eles.
A ordem dos eventos para uma exceção gerada é a seguinte:
O runtime orienta a pilha procurando a cláusula catch apropriada ou, no caso de SEH, um filtro exceto para SEH, para capturar a exceção. As cláusulas Catch são pesquisadas primeiro em ordem lexical e, em seguida, reduzem dinamicamente a pilha de chamadas.
Depois que o identificador correto for encontrado, a pilha será desenrolada até esse ponto. Para cada chamada de função na pilha, seus objetos locais são destruídos e blocos __finally são executados, da maioria aninhado para fora.
Depois que a pilha for desenrolada, a cláusula catch será executada.
Capturando tipos não gerenciados
Quando um tipo de objeto não gerenciado é gerado, ele é encapsulado com uma exceção do tipo SEHException. Ao pesquisar a cláusula catch
apropriada, há duas possibilidades.
Se um tipo C++ nativo for encontrado, a exceção será desembrulhada e comparada ao tipo encontrado. Essa comparação permite que um tipo C++ nativo seja capturado da maneira normal.
No entanto, se uma cláusula
catch
do tipo SEHException ou qualquer uma de suas classes base for examinada primeiro, a cláusula interceptará a exceção. Portanto, você deve colocar todas as cláusulas catch que capturam tipos C++ nativos primeiro antes de qualquer cláusula catch de tipos CLR.
Observe que
catch(Object^)
e
catch(...)
ambos capturarão qualquer tipo lançado, incluindo exceções SEH.
Se um tipo não gerenciado for capturado por catch(Object^), ele não destruirá o objeto gerado.
Ao lançar ou capturar exceções não gerenciadas, recomendamos que você use a opção do compilador /EHsc em vez de /EHs ou /EHa.