Compartir a través de


Conceptos básicos del uso de excepciones administradas

En este tema se describe el control de excepciones en las aplicaciones administradas. Es decir, una aplicación que se compila con la opción del compilador /clr.

En este tema

Comentarios

Si compila con la opción /clr, puede controlar las excepciones CLR, y la clase estándar Exception proporciona muchos métodos útiles para procesar excepciones CLR y se recomienda como clase base para las clases de excepción definidas por el usuario.

No se admite la captura de tipos de excepción derivados de una interfaz en /clr. Además, Common Language Runtime no permite capturar excepciones de desbordamiento de pila; una excepción de desbordamiento de pila finalizará el proceso.

Para obtener más información sobre las diferencias en el control de excepciones en aplicaciones administradas y no administradas, vea Diferencias en el comportamiento del control de excepciones en Extensiones administradas para C++ .

Lanzamiento de excepciones en /clr

La expresión throw de C++ se extiende para lanzar un identificador de un tipo CLR. En el ejemplo siguiente se crea un tipo de excepción personalizado y, a continuación, se inicia una instancia de ese 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;
}

Un tipo de valor debe ser encapsulado (boxing) antes de ser lanzado.

// clr_exception_handling_2.cpp
// compile with: /clr /c
value struct MyValueStruct {
   int i;
};

void GlobalFunction() {
   MyValueStruct v = {11};
   throw (MyValueStruct ^)v;
}

Bloques Try/Catch para extensiones del CLR

Se puede usar la misma estructura de bloques try/catch para capturar excepciones CLR y 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 );
      }
   }
}

Salida

In 'catch(CMyClass& catchC)'
2
In 'catch(MyStruct^ catchException)'
11

Orden de liberación para objetos de C++

El desenredado se produce para cualquier objeto de C++ con destructores que puedan estar en la pila del entorno de ejecución entre la función de inicio y la función de control. Dado que los tipos CLR se asignan en el montón, el desenrollado no les es aplicable.

El orden de los eventos de una excepción lanzada es el siguiente:

  1. El entorno de ejecución recorre la pila buscando la cláusula catch adecuada o, en el caso de SEH, un filtro excepto para SEH, para capturar la excepción. Las cláusulas catch se buscan primero en orden léxico y luego dinámicamente a lo largo de la pila de llamadas.

  2. Una vez que se encuentra el controlador correcto, la pila se desenreda hasta ese punto. Para cada llamada de función en la pila, sus objetos locales se destruyen y, por último, los bloques se ejecutan, desde el más anidado hacia fuera.

  3. Una vez desenredada la pila, se ejecuta la cláusula catch.

Captura de tipos no administrados

Cuando se lanza un tipo de objeto no administrado, se envuelve con una excepción de tipo SEHException. Al buscar la cláusula adecuada catch, hay dos posibilidades.

  • Si se encuentra un tipo nativo de C++, la excepción se desencapsula y se compara con el tipo encontrado. Esta comparación permite capturar un tipo nativo de C++ de la manera normal.

  • Sin embargo, si se examina primero una cláusula catch de tipo SEHException o cualquiera de sus clases base, la cláusula interceptará la excepción. Por lo tanto, debe colocar primero todas las cláusulas catch que detecten los tipos nativos de C++ antes de cualquier cláusula catch de los tipos CLR.

Observe lo siguiente:

catch(Object^)

y

catch(...)

detectarán cualquier tipo iniciado, incluidas las excepciones SEH.

Si catch(Object^) detecta un tipo no administrado, no destruirá el objeto lanzado.

Al iniciar o detectar excepciones no administradas, se recomienda usar la opción del compilador /EHsc en lugar de /EHs o /EHa.

Consulte también

Control de excepciones
safe_cast
Control de excepciones