Diferencias en el comportamiento del control de excepciones en /CLR
Conceptos básicos en el uso de excepciones administradas describe el control de excepciones en las aplicaciones administradas. En este tema se describen de forma detallada, las diferencias con respecto al comportamiento estándar del control de excepciones y algunas restricciones. Para más información, consulte La función _set_se_translator.
Salida de un bloque finally
En el código nativo de C/C++, se permite salir de un bloque __finally mediante el control de excepciones estructurado (SEH), aunque aparece una advertencia. En /clr, al salir de un bloque finally se produce un error:
// clr_exception_handling_4.cpp
// compile with: /clr
int main() {
try {}
finally {
return 0; // also fails with goto, break, continue
}
} // C3276
Aparición de excepciones en un filtro de excepciones
Cuando se produce una excepción durante el procesamiento de un filtro de excepciones en código administrado, la excepción se detecta y se trata como si el filtro devolviera 0.
Esto contrasta con el comportamiento del código nativo en el que se genera una excepción anidada, se establece el campo ExceptionRecord de la estructura EXCEPTION_RECORD (tal como lo devuelve GetExceptionInformation) y el campo ExceptionFlags establece el bit 0x10. En el siguiente ejemplo, se muestra esta diferencia de comportamiento:
// clr_exception_handling_5.cpp
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#ifndef false
#define false 0
#endif
int *p;
int filter(PEXCEPTION_POINTERS ExceptionPointers) {
PEXCEPTION_RECORD ExceptionRecord =
ExceptionPointers->ExceptionRecord;
if ((ExceptionRecord->ExceptionFlags & 0x10) == 0) {
// not a nested exception, throw one
*p = 0; // throw another AV
}
else {
printf("Caught a nested exception\n");
return 1;
}
assert(false);
return 0;
}
void f(void) {
__try {
*p = 0; // throw an AV
}
__except(filter(GetExceptionInformation())) {
printf_s("We should execute this handler if "
"compiled to native\n");
}
}
int main() {
__try {
f();
}
__except(1) {
printf_s("The handler in main caught the "
"exception\n");
}
}
Output
Caught a nested exception
We should execute this handler if compiled to native
Regeneraciones desasociadas
/clr no admite volver a generar una excepción fuera de un identificador de capturas (conocido como una regeneración desasociada). Las excepciones de este tipo se tratan como una nueva regeneración de C++ estándar. Si se encuentra un rethrow desasociado cuando hay una excepción administrada activa, la excepción se encapsula como una excepción de C++ y, después, se vuelve a iniciar. Las excepciones de este tipo solo se pueden detectar como una excepción del tipo SEHException.
En el ejemplo siguiente se muestra una excepción administrada que se vuelve a iniciar como una excepción de C++:
// clr_exception_handling_6.cpp
// compile with: /clr
using namespace System;
#include <assert.h>
#include <stdio.h>
void rethrow( void ) {
// This rethrow is a dissasociated rethrow.
// The exception would be masked as SEHException.
throw;
}
int main() {
try {
try {
throw gcnew ApplicationException;
}
catch ( ApplicationException^ ) {
rethrow();
// If the call to rethrow() is replaced with
// a throw statement within the catch handler,
// the rethrow would be a managed rethrow and
// the exception type would remain
// System::ApplicationException
}
}
catch ( ApplicationException^ ) {
assert( false );
// This will not be executed since the exception
// will be masked as SEHException.
}
catch ( Runtime::InteropServices::SEHException^ ) {
printf_s("caught an SEH Exception\n" );
}
}
Output
caught an SEH Exception
Filtros de excepciones y EXCEPTION_CONTINUE_EXECUTION
Si un filtro devuelve EXCEPTION_CONTINUE_EXECUTION
en una aplicación administrada, se trata como si el filtro devolviera EXCEPTION_CONTINUE_SEARCH
. Para más información sobre estas constantes, consulte Instrucción try-except.
En el ejemplo siguiente se muestra esta diferencia:
// clr_exception_handling_7.cpp
#include <windows.h>
#include <stdio.h>
#include <assert.h>
int main() {
int Counter = 0;
__try {
__try {
Counter -= 1;
RaiseException (0xe0000000|'seh',
0, 0, 0);
Counter -= 2;
}
__except (Counter) {
// Counter is negative,
// indicating "CONTINUE EXECUTE"
Counter -= 1;
}
}
__except(1) {
Counter -= 100;
}
printf_s("Counter=%d\n", Counter);
}
Output
Counter=-3
La función set_se_translator
La función translator establecida por una llamada a _set_se_translator
solo afecta a las capturas en código no administrado. En el ejemplo siguiente se muestra esta limitación:
// clr_exception_handling_8.cpp
// compile with: /clr /EHa
#include <iostream>
#include <windows.h>
#include <eh.h>
#pragma warning (disable: 4101)
using namespace std;
using namespace System;
#define MYEXCEPTION_CODE 0xe0000101
class CMyException {
public:
unsigned int m_ErrorCode;
EXCEPTION_POINTERS * m_pExp;
CMyException() : m_ErrorCode( 0 ), m_pExp( NULL ) {}
CMyException( unsigned int i, EXCEPTION_POINTERS * pExp )
: m_ErrorCode( i ), m_pExp( pExp ) {}
CMyException( CMyException& c ) : m_ErrorCode( c.m_ErrorCode ),
m_pExp( c.m_pExp ) {}
friend ostream& operator <<
( ostream& out, const CMyException& inst ) {
return out << "CMyException[\n" <<
"Error Code: " << inst.m_ErrorCode << "]";
}
};
#pragma unmanaged
void my_trans_func( unsigned int u, PEXCEPTION_POINTERS pExp ) {
cout << "In my_trans_func.\n";
throw CMyException( u, pExp );
}
#pragma managed
void managed_func() {
try {
RaiseException( MYEXCEPTION_CODE, 0, 0, 0 );
}
catch ( CMyException x ) {}
catch ( ... ) {
printf_s("This is invoked since "
"_set_se_translator is not "
"supported when /clr is used\n" );
}
}
#pragma unmanaged
void unmanaged_func() {
try {
RaiseException( MYEXCEPTION_CODE,
0, 0, 0 );
}
catch ( CMyException x ) {
printf("Caught an SEH exception with "
"exception code: %x\n", x.m_ErrorCode );
}
catch ( ... ) {}
}
// #pragma managed
int main( int argc, char ** argv ) {
_set_se_translator( my_trans_func );
// It does not matter whether the translator function
// is registered in managed or unmanaged code
managed_func();
unmanaged_func();
}
Output
This is invoked since _set_se_translator is not supported when /clr is used
In my_trans_func.
Caught an SEH exception with exception code: e0000101
Consulte también
Control de excepciones
safe_cast
Control de excepciones en MSVC