Exceptions : libération d'objets dans les exceptions
Cet article explique le besoin et la méthode de libération d’objets lorsqu’une exception se produit. Les sujets abordés sont les suivants :
Les exceptions levées par l’infrastructure ou par votre application interrompent le flux de programme normal. Par conséquent, il est très important de garder une trace étroite des objets afin que vous puissiez les supprimer correctement au cas où une exception est levée.
Il existe deux méthodes principales pour ce faire.
Gérez les exceptions localement à l’aide des
try
mot clécatch
, puis détruisez tous les objets avec une seule instruction.Détruisez un objet dans le
catch
bloc avant de lever l’exception en dehors du bloc pour une gestion supplémentaire.
Ces deux approches sont illustrées ci-dessous sous forme de 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
ne sera pas supprimé si une exception est levée par SomeFunc
. L’exécution passe directement au gestionnaire d’exceptions externe suivant, en contournant la sortie de la fonction normale et le code qui supprime l’objet. Le pointeur vers l’objet sort de l’étendue lorsque l’exception quitte la fonction, et la mémoire occupée par l’objet ne sera jamais récupérée tant que le programme est en cours d’exécution. Il s’agit d’une fuite de mémoire ; elle serait détectée à l’aide des diagnostics de mémoire.
Gestion de l’exception localement
Le paradigme try/catch fournit une méthode de programmation défensive pour éviter les fuites de mémoire et s’assurer que vos objets sont détruits lorsque des exceptions se produisent. Par exemple, l’exemple présenté 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 le gérer localement. Il quitte ensuite la fonction normalement et détruit l’objet. L’aspect important de cet exemple est qu’un contexte pour intercepter l’exception est établi avec les blocs try/catch . Sans cadre d’exception locale, la fonction ne sait jamais qu’une exception a été levée et n’aurait pas la possibilité de quitter normalement et de détruire l’objet.
Levée d’exceptions après destruction d’objets
Une autre façon de gérer les exceptions consiste à les transmettre au contexte de gestion des exceptions externe suivant. Dans votre catch
bloc, vous pouvez effectuer une propre up de vos objets alloués localement, puis lever l’exception pour un traitement ultérieur.
La fonction de levée peut ou ne pas avoir besoin de libérer des objets de tas. Si la fonction libère toujours l’objet tas avant de retourner dans le cas normal, la fonction doit également libérer l’objet tas avant de lever l’exception. En revanche, si la fonction ne désalloue pas normalement l’objet avant de retourner dans le cas normal, vous devez décider si l’objet tas doit être désalloué.
L’exemple suivant montre comment les objets alloués localement peuvent être propre vers le haut :
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 désalloue automatiquement les objets frame ; le destructeur de l’objet frame est également appelé.
Si vous appelez des fonctions qui peuvent lever des exceptions, vous pouvez utiliser des blocs try/catch pour vous assurer que vous interceptez les exceptions et que vous avez la possibilité de détruire les objets que vous avez créés. En particulier, sachez que de nombreuses fonctions MFC peuvent lever des exceptions.
Pour plus d’informations, consultez Exceptions : Intercepter et supprimer des exceptions.