2009-07-29 6 views
7

Pourquoi ce code pas provoque des fuites de mémoire?std :: auto_ptr, supprime [] et fuit

int iterCount = 1000; 
int sizeBig = 100000; 
for (int i = 0; i < iterCount; i++) 
{ 
    std::auto_ptr<char> buffer(new char[sizeBig]); 
} 

Windows XP sp2, compilateur: BCB.05.03

+0

Dans la plupart des cas, si vous associez new avec delete [] et vice versa pour des types non triviaux, cela ne provoque pas de fuite - le programme se bloque simplement lorsque vous essayez de libérer de la mémoire. – sharptooth

+3

Vous pouvez essayer d'utiliser boost :: scoped_array au lieu de std :: auto_ptr –

Répondre

15

Parce que vous êtes (un) chance. auto_ptr appelle delete, et non delete []. C'est un comportement indéfini.

Essayez de faire quelque chose comme ça et voir si vous obtenez aussi chanceux:

struct Foo 
{ 
    char *bar; 
    Foo(void) : bar(new char[100]) { } 
    ~Foo(void) { delete [] bar; } 
} 

int iterCount = 1000; 
int sizeBig = 100000; 
for (int i = 0; i < iterCount; i++) 
{ 
    std::auto_ptr<Foo> buffer(new Foo[sizeBig]); 
} 

L'idée ici est que votre destructor pour Foo ne sera pas appelé.


La raison est quelque chose comme ceci: Quand vous dites delete[] p, la mise en œuvre de delete[] est supposé aller à chaque élément du tableau, appelez son destructor, puis libérer la mémoire pointée par p. De même, delete p est supposé appeler le destructeur sur p, puis libérer la mémoire.

char 's n'ont pas de destructeur, donc il va juste supprimer la mémoire pointée par p. Dans mon code ci-dessus, il est pas va détruire chaque élément dans le tableau (parce qu'il n'appelle pas delete[]), donc certains Foo laissera leur variable de barre locale non supprimée.

+0

Oui, je suis malchanceux :) Merci pour l'explication. – Xeningem

+0

J'ai compilé ceci, mais je reçois le message d'erreur '_BLOCK_TYPE_IS_VALID (pHead-> nBlockUse)', le programme se bloque ..cela semble indiquer qu'il est supprimé deux fois mais ne sait pas comment cela pourrait se produire – zar

+0

Le destructeur de 'Foo' serait en fait appelé' iterCount's mais notez 'iterCount' *' sizeBig' fois – zar

3

Le paramètre auto_ptr ne restera actif que pendant la durée de l'itération de la boucle et libèrera l'objet qui lui est connecté à la fin de l'itération.

Le compilateur peut voir que dans ce cas nouveau [] peut allouer de l'espace de la même manière que nouvelle - sans stocker le nombre d'éléments partout car il n'y a pas besoin d'appeler char trivial Destructeurs - et voilà pourquoi plus tard lorsque supprimer est appelé par le destructor de auto_ptr au lieu de supprimer [] il ne pose aucun problème puisque le bloc de mémoire a effectivement été alloué dans la nouvelle façon d » des et que l'allocation peut être associée à supprimer.

Ceci est un exemple de chose à ne pas faire. C'est au compilateur de décider s'il faut remplacer nouveau [] par nouveau. En utilisant supprimer au lieu de supprimer [] et vice versa est un comportement indéfini.

Voir Why would you write something like this? (intentionally not using delete [] on an array) pour la discussion de supprimer vs supprimer [].

+0

Donc comme GMan dit: c'est pure chance * delete * est équivalent à * delete [] * ici? – xtofl

+1

Eh bien, oui, c'est un résultat du compilateur essayant d'être intelligent et économisant le développeur. – sharptooth

+3

Ce n'est pas parce que le compilateur est intelligent, c'est parce que le compilateur est paresseux et fait la chose la plus facile (ce qui signifie que l'allocation de mémoire pour un élément et un tableau fonctionne exactement de la même manière). Bien sûr, il s'agit des États-Unis, c'est donc une «pure chance» que cela fonctionne dans une implémentation donnée - et IIRC il y a quelques implémentations réelles où cela ne fonctionne pas. –

Questions connexes