2012-10-04 1 views
6

Un jour avant, j'ai fait face à cette question lors d'une interview. Alors, guide-moi. Comment nettoyer les ressources initialisées si une exception est levée du constructeur en C++?Comment nettoyer les ressources initialisées si une exception est levée du constructeur en C++

+0

Pourquoi est-ce être proche a été voté? Ceci est un Q valide. Ne votez pas Q parce que vous ne l'aimez pas ou que vous ne le comprenez pas.Faites voter seulement et seulement s'il est admissible à la fermeture conformément à la politique de SO. –

Répondre

6

L'astuce consiste à utiliser RAII (l'acquisition de ressources est l'initialisation) pour gérer les ressources.

Si vous avez des membres de pointeur, utilisez des pointeurs intelligents au lieu de pointeurs bruts qui effectueront automagiquement le travail de nettoyage une fois qu'une exception est levée du constructeur.

Bonne lecture:
Herb Sutter's excellent GotW article "Construction Failures"

+0

+1 pour le lien – Dialecticus

1

Utilisez les membres de données qui libèrent les ressources quand ils sont détruits (aka RAII).

Par exemple:

struct TwoStrings { 
    std::string string1; 
    std::string string2; 
    TwoStrings(const std::string &input) : string1(input) { 
     if (!input[1] == ':') { 
      throw std::logic_error('not a Windows absolute path'); 
      // yes, absolute paths can begin \\, this is a toy example 
     } 
     if (input.back() == '\\') { 
      string2 = input; 
     } else { 
      string2 = input + "\\"; 
     } 
    } 
}; 

Si le constructeur lance (soit logic_error ou bad_alloc), le membre de données déjà initialisé string1 est détruit, ce qui libère la ressource. Pour cette raison, string2 est également détruit, mais si le constructeur lance alors string2 doit toujours être vide, donc cela n'a pas d'effet particulier.

string est un exemple de classe qui gère les ressources, mais il y en a beaucoup d'autres. Les plus flexibles d'entre eux sont appelés "pointeurs intelligents" et peuvent être configurés pour gérer à peu près n'importe quelle ressource, pas seulement des tableaux de caractères auto-alloués comme string.

1

Lorsqu'une exception est levée, la pile est déroulée jusqu'au point de capture. En conséquence, tout ce qui avait été construit en elle est détruit. Il est donc important de placer chaque ressource sensible dans une classe dont le destructeur s'occupe de l'élimination de la ressource associée. Si la ressource est un objet affecté par le tas, les pointeurs intelligents font exactement cela (supprimer l'objet point après sa destruction), si la ressource est un fichier ouvert, un flux le ferme après destruction. Tout le reste nécessite un wrapper personnalisé. Mais notez que les nombreuses "ressources" sont représentées par des gestionnaires qui sont eux-mêmes void *. Ceci permet également d'utiliser smart poitner, en initialisant ensuite avec la ressource allouée et en spécifiant une fonction de suppression. Ce que la technique joue mieux est beaucoup plus une question de goût et d'opportunité.

1

La meilleure façon de le faire est: Allouer toutes les ressources dans les constructeurs et désaffecter n'importe lequel dans les destructeurs.

Les modèles en C++ sont très utiles dans ce but car nous pouvons rendre la création d'objets atomique.

+0

Vous devez trouver des exemples et un peu plus d'explications car vous voyez que cette question a déjà assez bien répondu à quelques-uns. –

Questions connexes