2010-09-10 10 views
2

Je ne vois pas la raison de la fuite ci-dessous.C++ valgrind fuites possibles sur chaîne STL

#include <iostream> 
#include <cstdlib> 

int fail(const std::string str) 
{ 
    std::cerr<< str << std::endl; 
    exit(1); 
} 

const std::string usage() 
{ 
    std::string a = "a"; 
    return a; 
} 

int main() 
{ 
    fail(usage()); 
    return 0; 
} 

dit Valgrind:

==7238== 14 bytes in 1 blocks are possibly lost in loss record 1 of 1 
==7238== at 0x402377E: operator new(unsigned) (vg_replace_malloc.c:224) 
==7238== by 0x40E7C03: std::string::_Rep::_S_create(unsigned, unsigned, 
std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.10) 
==7238== by 0x40E8864: (within /usr/lib/libstdc++.so.6.0.10) 
==7238== by 0x40E89D5: std::string::string(char const*, std::allocator<char> const&) 
(in /usr/lib/libstdc++.so.6.0.10) 
==7238== by 0x80488EC: usage() (main.cpp:12) 
==7238== by 0x804897C: main (main.cpp:18) 
==7238== LEAK SUMMARY: 
==7238== definitely lost: 0 bytes in 0 blocks. 
==7238==  possibly lost: 14 bytes in 1 blocks. 
==7238== still reachable: 0 bytes in 0 blocks. 
==7238==   suppressed: 0 bytes in 0 blocks. 

Le problème est dans la fonction échouer(). Comme il se termine(), la mémoire est divulguée.

Si je commente la sortie (1); alors il n'y a pas de fuite possible.

En outre, si je change la signature de int échec (const std :: string str) à int échec (const char * str)

alors il n'y a pas de fuite possible aussi bien. Je n'aime pas cette solution, car j'utilise fail (string + (LINE)), mais quoi qu'il en soit, que se passe-t-il ici?

Je serai heureux si quelqu'un peut expliquer.

Merci!

(upps. Même question posée je suppose, désolé! Valgrind reports memory leak when assigning a value to a string)

Répondre

21

Lorsque vous appelez exit(), les objets des Destructeurs automatiques (variables locales) ne sont pas appelés.

Dans votre exemple spécifique, le destructeur std::string n'est pas appelé, donc la mémoire détenue par le std::string n'est jamais libérée.

La raison pour laquelle il n'y a pas de fuite si vous avez fail() prendre un const char* est qu'il n'y a pas de destructeur pour const char*; rien n'est désaffecté lorsqu'un pointeur est détruit. Si le pointeur pointe vers une mémoire allouée dynamiquement, cette mémoire doit être libérée (par vous) avant que le programme ne se termine, sinon vous avez une fuite de mémoire. Si elle pointe vers un littéral de chaîne, il n'y a pas de fuite de mémoire car les littéraux de chaîne ont une durée de stockage statique (c'est-à-dire qu'ils existent pour toute la durée de vie de votre programme). James McNellis a déjà écrit une bonne réponse.

+1

Ce document dit que vous avez tort: ​​http://www.cplusplus.com/reference/clibrary/cstdlib/exit/ – Klaim

+10

@Klaim: Je ne vois pas où ce document dit que je me trompe, mais si elle Est-ce que c'est faux? Pour citer le standard C++ (§18.3/8): "Les objets automatiques ne sont pas détruits à la suite de l'appel' exit() '." –

+0

Puis cette phrase «Termine le processus normalement, effectuant le nettoyage régulier pour terminer les processus». est trompeur? Quoi qu'il en soit, la norme dit que vous avez raison, alors vous avez raison. (Je ne peux pas voter jusqu'à ce que vous éditiez si) – Klaim

8

Mais je voudrais ajouter quelques choses:

  1. Il est toujours une bonne chose d'écrire un logiciel d'une manière qu'il n'a pas besoin d'appeler exit() - ce qui vous aide à améliorer la conception globale, et préciser comprendre les durées de vie des objets (sauf dans des cas très spéciaux - plutôt bas - niveau ..). Comme vous le voyez ici, ceci est important lorsque vous utilisez des outils comme valgrind! Une procédure d'arrêt "propre" vous fait vous sentir en sécurité, alors tout a bien fonctionné, comme vous l'attendiez;) Une procédure d'arrêt propre dans des cas exceptionnels devrait être une exigence de chaque logiciel.

Vous devriez envisager de throw une exception au lieu d'appeler une fonction fail(). Lorsqu'une exception est levée, la pile sera déroulée, ainsi le destructeur std::string dans votre cas sera appelé.