Compartir a través de


Excepciones: Cambios en las macros de excepción en la versión 3.0

Este es un tema avanzado.

En la versión 3.0 y posteriores de MFC, las macros de control de excepciones se modificaron para usar excepciones de C++. En este artículo, se indica cómo esos cambios pueden afectar al comportamiento del código existente que usa las macros.

En este artículo se tratan los temas siguientes:

Tipos de excepción y la macro CATCH

En versiones anteriores de MFC, la macro CATCH usaba información de tipo en tiempo de ejecución de MFC para determinar el tipo de una excepción; en otras palabras, el tipo de la excepción se determina en el sitio catch. Sin embargo, con las excepciones de C++, el tipo de excepción siempre lo determina en el sitio throw el tipo del objeto de excepción que se genera. Esto provocará incompatibilidades en el caso poco frecuente en el que el tipo del puntero al objeto que se genera difiera del tipo del objeto que se genera.

En el ejemplo siguiente, se muestra la consecuencia de esta diferencia entre MFC en versión 3.0 y las versiones anteriores:

TRY
{
   THROW((CException*) new CCustomException());
}
CATCH(CCustomException, e)
{
   TRACE("MFC 2.x will land here\n");
}
AND_CATCH(CException, e)
{
   TRACE("MFC 3.0 will land here\n");
}
END_CATCH

Este código tiene un comportamiento distinto en la versión 3.0, porque el control siempre pasa al primer bloque catch con una declaración de excepción coincidente. Resultado de la expresión throw

THROW((CException*) new CCustomException());

se genera como CException*, incluso si se construye como CCustomException. La macro CATCH en las versiones 2.5 y anteriores de MFC usa CObject::IsKindOf para probar el tipo en tiempo de ejecución. Dado que la expresión

e->IsKindOf(RUNTIME_CLASS(CException));

es true, el primer bloque catch detecta la excepción. En la versión 3.0, que usa excepciones de C++ para implementar muchas de las macros de control de excepciones, el segundo bloque catch coincide con la CException generada.

El código como este es poco común. Por lo general, aparece cuando se pasa un objeto de excepción a otra función que acepta una CException* genérica, realiza el procesamiento previo a la generación de la excepción y, por último, genera la excepción.

Para solucionar este problema, mueva la expresión throw de la función al código de llamada y genere una excepción del tipo real conocido para el compilador en el momento en que se genera la excepción.

Volver a generar excepciones

Un bloque catch no puede generar el mismo puntero de excepción que detectó.

Por ejemplo, este código era válido en las versiones anteriores, pero tendrá resultados inesperados con la versión 3.0:

TRY
{
   // Do something to throw an exception.
   AfxThrowUserException();
}
CATCH(CException, e)
{
   THROW(e);    // Wrong. Use THROW_LAST() instead
}
END_CATCH
   }

El uso de THROW en el bloque catch hace que se elimine el puntero e, de modo que el sitio catch externo reciba un puntero no válido. Use THROW_LAST para volver a generar e.

Para más información, consulte Excepciones: Detección y eliminación de excepciones.

Consulte también

Control de excepciones