Partilhar via


Conceitos básicos no uso de exceções gerenciadas

Este tópico discute o tratamento de exceções em aplicativos gerenciados. Ou seja, um aplicativo que é compilado com a opção de compilador /clr .

Neste tópico

Observações

Se você compilar com a opção /clr , poderá manipular exceções CLR, bem como a classe padrão Exception fornece muitos métodos úteis para processar exceções CLR e é recomendada como uma classe base para classes de exceção definidas pelo usuário.

A captura de tipos de exceção derivados de uma interface não é suportada em /clr. Além disso, o Common Language Runtime não lhe permite capturar 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 Extensões gerenciadas para C++.

Lançando exceções em /clr

A expressão de lançamento C++ é estendida para lançar uma referência 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 encaixotado 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;
}

Blocos Try/Catch para extensões CLR

A mesma try/catch estrutura de bloco pode ser usada para capturar exceções CLR e 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 );
      }
   }
}

Resultado

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 possam 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 montão, o desenrolamento não se aplica a eles.

A ordem dos eventos para uma exceção lançada é a seguinte:

  1. O runtime percorre a pilha procurando a cláusula de captura apropriada ou, no caso de SEH, um filtro except para SEH, para capturar a exceção. As cláusulas catch são procuradas primeiro na ordem lexical e, em seguida, dinamicamente na pilha de chamadas.

  2. Uma vez que o manipulador correto é encontrado, a pilha é desenrolada até esse ponto. Para cada chamada de função na pilha, seus objetos locais são destruídos e __finally blocos são executados, da maioria aninhada para fora.

  3. Uma vez que a pilha é desenrolada, a cláusula catch é executada.

Capturando tipos não gerenciados

Quando um tipo de objeto não gerenciado é lançado, ele é encapsulado com uma exceção do tipo SEHException. Ao procurar a cláusula adequada catch , existem duas possibilidades.

  • Se um tipo C++ nativo for encontrado, a exceção será desempacotada 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 do tipo catch ou qualquer uma das suas classes base for examinada primeiro, a cláusula intercetará 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.

Tenha em atenção que

catch(Object^)

e ainda

catch(...)

ambos pegarão qualquer tipo jogado, incluindo exceções SEH.

Se um tipo não gerenciado for capturado por catch(Object^), ele não destruirá o objeto lançado.

Ao lançar ou capturar exceções não gerenciadas, recomendamos que você use a opção de compilador /EHsc em vez de /EHs ou /EHa.

Ver também

Tratamento de exceções
safe_cast
Tratamento de exceções