2010-11-24 37 views
13

Le code C++ suivant est-il une fuite de mémoire? Si je comprends bien, push_back de toute collection/conteneur std fait toujours une copie. Donc, si la nouvelle chaîne est copiée, rien ne peut jamais supprimer la chaîne new'd droite? puisqu'il n'y a pas de référence après le push_back ...C++: push_back (new Object()) est-il une fuite de mémoire?

Est-ce que je suis correct ou mauvais ici?

Merci.

JBU

edit: Je pense que je me trompe, car nouvelle retournera un pointeur ... nous avons toujours le pointeur pour pouvoir supprimer la nouvelle chaîne

+1

Cela dépend de la définition de 'list'. –

+3

Dépend de ce que 'list' est. En supposant que c'est une 'std :: liste ', @UncleBens est correct: il peut toujours être possible de nettoyer correctement la plupart du temps. Mais vous devez faire ce nettoyage manuellement; 'std :: list' ne le fera pas pour vous. – aschepler

+0

Oui. Parce que la variable 'list' est en fait d'un type qui a une fonction appelée 'push_back' avec un corps vide. –

Répondre

6

Non, les magasins de vecteur pointeurs et la copie est faite du pointeur. Vous pouvez supprimer l'objet n'importe quand plus tard.

(Vous pouvez obtenir une fuite, si l'instruction arrive à lancer une exception et vous n'attraper et manipuler correctement. Voilà pourquoi vous pouvez envisager d'utiliser des pointeurs intelligents.)

+3

"si l'instruction arrive à lancer une exception et que vous ne l'attrapez pas et ne la manipulez pas correctement" - dans le cas de cette instruction, il n'y a aucun moyen de la gérer correctement, vraiment. Si 'push_back' se lance, alors il n'a pas stocké le pointeur, et il n'y a aucun moyen de le libérer parce que ce code appelant n'a pas non plus le pointeur. Je suppose qu'en théorie, vous pourriez peut-être faire quelque chose avec 'String :: operator new', mais cela ne semble pas amusant. –

1

Vous avez raison, à condition que rien supprime la chaîne lorsqu'elle est supprimée de la liste.

1

Oui, il s'agit d'une fuite de mémoire qui vous permet en quelque sorte de supprimer les pointeurs contenus.

Et le meilleur moyen d'y parvenir est d'utiliser un pointeur intelligent. Par exemple, shared_ptr de Boost ou shared_ptr de C++ 0x.

+0

scaled_ptr ?? Voulez-vous dire shared_ptr? –

+0

@Fred: euh. peut-être ... –

+0

La seule autre chose que je pourrais penser que vous vouliez dire était scoped_ptr, mais cela ne fonctionnera pas dans un conteneur car il est non-jetable. –

4

Si je voyais ce code je serais très méfiant une fuite de mémoire était possible. Sur la surface, il semble ajouter un String* attribué dans un list<String*>. D'après mon expérience, cela est souvent suivi d'un mauvais code de gestion des erreurs qui ne libère pas correctement la mémoire allouée.

Bien que cela soit dangereux dans de nombreuses circonstances, il ne s'agit pas nécessairement d'une fuite de mémoire. Prenons l'exemple suivant:

class Container { 
    ~Container() { 
    std::list<String*>::iterator it = list.begin(); 
    while (it != list.end()) { 
     delete *it; 
     it++; 
    } 
    } 

    void SomeMethod() { 
    ... 
    list.push_back(new String("hi")); 
    } 

    std::list<String*> list; 
} 

Dans ce code il n'y a pas de fuite, car la classe contenant est responsable de la mémoire allouée et le libérer dans la destructor.

EDIT

Comme aschepler a souligné il y a encore une fuite si la méthode push_back jette une exception.

+3

Si l'appel à 'push_back' renvoie une exception, il s'agit toujours d'une fuite. – aschepler

+1

Il existe également un risque de double suppression sauf si vous déclarez un constructeur de copie et un opérateur d'affectation de copie. –

0

No.

Vous pouvez supprimer l'objet en faisant:

delete list[i]; 
list.erase(list.begin() + i); 

ou effacer toute la liste par:

for (unsigned int i = 0; i < list.size(); ++i) 
{ 
    delete list[i]; 
} 
list.clear(); 
0
list.push_back(new String("hi")); 

Pourquoi vous allouez cordes dynamiques en premier lieu?Sauf si vous voulez communiquer entre les différentes parties de votre programme en changeant les chaînes (ce qui serait tout à fait inhabituel), se débarrasser du pointeur:

std::list<std::string> list;   // note: no pointer! 
list.push_back(std::string("hi")); // explicitly create temporary 
list.push_back("hi");    // alternative: rely on coercion 
8

Oui, mais pas pour la raison que vous pensez. En fonction de la définition et de l'initialisation de list, push_back peut déclencher une exception. Si c'est le cas, le pointeur renvoyé par new est perdu et ne peut jamais être libéré.

Mais en supposant push_back retourne avec succès, il stocke une copie du pointeur retourné par new, et nous pouvons libérer la mémoire plus tard en appelant delete sur cette copie, donc pas de mémoire est perdu aussi longtemps que vous faites appel delete correctement.

+0

Wow, la seule bonne réponse sur sept! – Mankarse

+0

Je suis désolé, mais je ne pouvais pas comprendre si le pointeur est juste copié ou le pointé vers les données est également copié? Pour Ex: - String * str = new String ("HI"); list.push_back (str); Maintenant, puis-je appeler supprimer str et toujours être en mesure d'accéder à "HI" de la liste parce que valgrind montre une fuite à list.push_back sans aucun appel de suppression. –