Exceptions : modifications apportées aux macros d'exception dans la version 3.0
Il s’agit d’une rubrique avancée.
Dans MFC version 3.0 et ultérieure, les macros de gestion des exceptions ont été modifiées pour utiliser des exceptions C++. Cet article explique comment ces modifications peuvent affecter le comportement du code existant qui utilise les macros.
Cet article aborde les thèmes suivants :
Types d’exceptions et macro CATCH
Dans les versions antérieures de MFC, la macro CATCH a utilisé les informations de type d’exécution MFC pour déterminer le type d’une exception ; le type de l’exception est déterminé, en d’autres termes, sur le site catch . Toutefois, avec les exceptions C++, le type de l’exception est toujours déterminé au niveau du site levée par le type de l’objet d’exception levée. Cela entraîne des incompatibilités dans le cas rare où le type du pointeur vers l’objet levée diffère du type de l’objet levée.
L’exemple suivant illustre la conséquence de cette différence entre MFC version 3.0 et versions antérieures :
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
Ce code se comporte différemment dans la version 3.0, car le contrôle passe toujours au premier catch
bloc avec une déclaration d’exception correspondante. Résultat de l’expression throw
THROW((CException*) new CCustomException());
est levée comme un CException*
, même s’il est construit en tant que CCustomException
. La macro CATCH dans MFC versions 2.5 et antérieures utilise CObject::IsKindOf
pour tester le type au moment de l’exécution. Comme l’expression
e->IsKindOf(RUNTIME_CLASS(CException));
est vrai, le premier bloc catch intercepte l’exception. Dans la version 3.0, qui utilise des exceptions C++ pour implémenter de nombreuses macros de gestion des exceptions, le deuxième bloc catch correspond à l’exception levée CException
.
Le code comme celui-ci est rare. Il apparaît généralement lorsqu’un objet d’exception est passé à une autre fonction qui accepte un traitement générique CException*
, effectue le traitement « pré-levée » et lève enfin l’exception.
Pour contourner ce problème, déplacez l’expression levée de la fonction vers le code appelant et lèvez une exception du type réel connu du compilateur au moment où l’exception est générée.
Levée d’exceptions
Un bloc catch ne peut pas lever le même pointeur d’exception qu’il a intercepté.
Par exemple, ce code était valide dans les versions précédentes, mais aura des résultats inattendus avec la version 3.0 :
TRY
{
// Do something to throw an exception.
AfxThrowUserException();
}
CATCH(CException, e)
{
THROW(e); // Wrong. Use THROW_LAST() instead
}
END_CATCH
}
L’utilisation de THROW dans le bloc catch entraîne la suppression du pointeur e
, afin que le site catch externe reçoive un pointeur non valide. Utilisez THROW_LAST pour lever e
à nouveau .
Pour plus d’informations, consultez Exceptions : Intercepter et supprimer des exceptions.