exceptions : Récupération d'objets dans les exceptions
Cet article explique les besoins et la méthode pour libérer les objets lorsqu'une exception se produit. Les rubriques traitées ici sont les suivantes :
Gestion de l'exception localement
Levaer des exceptions après une destruction d'objets
Les exceptions levées par l'infrastructure ou par votre application interrompent le bon déroulement du programme. Par conséquent, il est très important de suivre les objets afin que vous puissiez correctement les supprimer au cas où une exception est levée.
Il existe deux méthodes principales d'effectuer cette opération :
Manipulez les exceptions localement à l'aide des mots clés try et catch, puis détruisez tous les objets avec une instruction.
Détruisez un objet dans le bloc catch avant de lever l'exception en dehors du bloc pour une gestion future.
Ces deux méthodes sont illustrées ci-dessous en tant que solutions à l'exemple problématique suivant :
void SomeFunc() // Problematic code
{
CPerson* myPerson = new CPerson;
// Do something that might throw an exception.
myPerson->SomeFunc();
// Now destroy the object before exiting.
// If SomeFunc above throws an exception this code will
// not be reached and myPerson will not be deleted.
delete myPerson;
}
Comme écrit ci-dessus, myPerson n'est pas supprimé si une exception est levée par SomeFunc. L'exécution accède directement au gestionnaire d'exceptions externe suivant, en ignorant la sortie standard de la fonction et le code qui supprime l'objet. Le pointeur à l'objet sort de l'étendue lorsque l'exception part de la fonction, et la mémoire occupée par l'objet ne sera jamais récupérée tant que le programme s'exécute. Il s'agit d'une fuite de mémoire ; elle est détectée à l'aide du diagnostic de mémoire.
Gestion locale de l'exception
Le paradigme try/catch fournit une méthode de programmation défensive pour éviter des fuites de mémoire et vous assurer que les objets sont détruits quand des exceptions se produisent. Par exemple, l'exemple indiqué précédemment dans cet article peut être réécrit comme suit :
void SomeFunc()
{
CPerson* myPerson = new CPerson;
try
{
// Do something that might throw an exception.
myPerson->SomeFunc();
}
catch( CException* e )
{
// Handle the exception locally
e->Delete();
}
// Now destroy the object before exiting.
delete myPerson;
}
Ce nouvel exemple configure un gestionnaire d'exceptions pour intercepter l'exception et la gérer localement. Il quitte ensuite la fonction normalement et détruit l'objet. Le point important de cet exemple est qu'un contexte pour intercepter l'exception est établi avec les blocs try/catch. Sans cadre local d'exception, la fonction ne saurait jamais qu'une exception a été levée et n'aurait pas l'occasion de se terminer normalement et de détruire l'objet.
Lever des exceptions après une destruction d'objets
Une autre méthode pour la gestion des exceptions est de les transmettre au contexte externe suivant de gestion des exceptions. Dans un bloc catch, vous pouvez effectuer le nettoyage de vos objets alloués localement puis lever une exception pour un traitement ultérieur.
La fonction levée peut ou ne peut pas avoir besoin de libérer les objets pile. Si la fonction libère toujours l'objet pile avant le retour au cas ordinaire, la fonction doit également libérer l'objet pile avant de lever d'exception. En revanche, si la fonction ne libère pas l'objet avant le retour au cas ordinaire, vous devez décider au cas par cas si l'objet pile doit être libéré.
L'exemple suivant montre comment les objets alloués localement peuvent être nettoyés :
void SomeFunc()
{
CPerson* myPerson = new CPerson;
try
{
// Do something that might throw an exception.
myPerson->SomeFunc();
}
catch( CException* e )
{
e->ReportError();
// Destroy the object before passing exception on.
delete myPerson;
// Throw the exception to the next handler.
throw;
}
// On normal exits, destroy the object.
delete myPerson;
}
Le mécanisme d'exception libère automatiquement les objets cadres ; le destructeur de l'objet cadre est également appelé.
Si vous appelez les fonctions qui peuvent lever des exceptions, vous pouvez utiliser des blocs try/catch pour vérifier que vous interceptez des exceptions et que vous disposez d'une occasion de détruire tous les objets créés. En particulier, sachez que de nombreuses fonctions de MFC peuvent lever des exceptions.
Pour plus d'informations, consultez Exceptions : Interception et suppression des exceptions.