Share via


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++ .

Inicio de excepciones en /clr

La expresión throw de C++ se extiende para iniciar un identificador en 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;
}

Se debe aplicar una conversión boxing a un tipo de valor antes de su inicio:

// 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 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 desenredado 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 desenredado no se les aplica.

El orden de los eventos de una excepción iniciada 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, a continuación, dinámicamente por 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 inicia un tipo de objeto no administrado, se encapsula 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 iniciado.

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