2009-06-14 6 views
15

J'ai beaucoup appris ces derniers jours sur la programmation en C++. J'adore ça :)
Je sais que je devrais libérer de la mémoire - les règles dorées "chaque malloc = libre" ou "chaque nouvelle = supprimer" existent maintenant dans mon monde, mais je les utilise pour des objets plutôt simples.
Qu'en est-il du vecteur? Quand je le peux, j'utilise vector.clear() mais cela ne suffit pas, car j'ai d'énormes fuites de mémoire.
Pourriez-vous me guider sur la façon dont je devrais traiter cette chose? Merci, vos commentaires m'ont fait penser à l'algoritme de cette application et je serai en mesure d'éliminer totalement le vecteur. : O
Désolé - J'ai commencé à expliquer mon cas d'utilisation ici et j'ai découvert ce dont j'avais vraiment besoin. C'est comme ça quand vous codez les 3 derniers jours pendant 18 heures par jour: | * Éditer 2
C'est fou. Par de petits changements de code, j'ai éliminé l'utilisation de la mémoire de 2x130 mb (en croissance constante) en 2x 13,5mb, taille constante. Merci de m'avoir fait réfléchir d'une autre façon.Dois-je supprimer le vecteur <string>?

Btw. un tel examen de code personnel a un nom - quelqu'un s'en souvient-il? C'est quand vous demandez à quelqu'un (même votre mère ou votre chien) et commencez à expliquer quel est votre problème - et soudain vous résolvez vous-même ce problème de 5 heures, simplement en essayant de le regarder d'un autre point de vue ou en résumant tout sur. Je me retrouve souvent attrapé sur ce ...

+5

Puisque vous êtes nouveau dans la gestion de la mémoire, vous pourriez peut-être expliquer comment vous savez que vous avez des fuites de mémoire. Certaines façons de mesurer les fuites de mémoire ne reflètent pas vraiment ce qui se passe. –

+0

Vous pouvez publier un exemple de code sur la façon dont vous utilisez la classe de vecteur. Par exemple, avez-vous des vecteurs de pointeurs vers des objets créés dynamiquement? –

+0

bien, je vois simplement que l'exécution de mon application entraîne de plus en plus de mémoire occupée. J'exécute des opérations assez faciles (faire des hachages md5 dans 2 processus, liés avec mpcih2), pour mon test c'est exactement 25 millions d'opérations. Un processus envoie aux autres paquets de données (chaînes) et le second calcule des hachages pour cela. À la fin de l'exécution, j'ai pris 2 x 130 mb. C'est beaucoup trop pour être normal. – IamDeveloper

Répondre

19

La règle est que lorsque vous effacez un vecteur d'objets, le destructeur de chaque élément sera appelé. D'un autre côté, si vous avez un vecteur de pointeurs, vector::clear() ne les appellera pas delete, et vous devrez les supprimer vous-même. Donc, si tout ce que vous avez est un vecteur de chaînes, et pas de pointeurs sur les chaînes, alors vos fuites de mémoire doivent être causées par autre chose. L'appel va détruire tous les objets qui sont actuellement dans v, mais il ne libérera pas la mémoire (on suppose que le vecteur sera bientôt rempli à nouveau).

+0

Cela s'applique-t-il en général? Si j'ai une classe qui a 'std: vector' comme l'une de ses propriétés, C++ appellera-t-il ce destructeur quand la classe sera détruite? –

+4

Oui. Lorsqu'un objet est détruit, le destructeur de tous ses membres de données est appelé. Mais comme je l'ai dit, faites attention à ce que vous stockez dans le vecteur. Si c'est un vecteur d'objets, les objets seront détruits avec le vecteur. Si c'est un vecteur de pointeurs, alors vous devez les supprimer vous-même. – Dima

7

Si vous voulez vraiment libérer la mémoire, l'idiome est

vector<string>().swap(v); 

Cela va créer un nouveau vecteur (temporaire) et échanger son contenu avec v. Le vecteur temporaire est ensuite détruit, libérant ainsi la mémoire.

+0

Maintenant, je vois l'intention derrière cela, mais cela me semble plutôt gênant. Et serait-ce la même chose que v.swap (vector ())? – ypnos

+2

Cela peut sembler gênant, mais c'est la façon idiomatique de diminuer 'v.capacity()'. Votre extrait ne sera pas compilé, puisque le vecteur () 'est un rvalue et ne peut pas être lié à une référence non-const. – avakar

+0

Pour clarifier: dans a.swap (b), a et b ne sont pas égaux. Le swap de membre a un argument, une référence non-const. Vous pouvez appeler des fonctions membres non-const des temporaires, donc dans a.swap (b), a peut être temporaire. Mais b est lié à une référence non-const et ne peut pas être temporaire. – MSalters

4

Le vecteur (comme tous les conteneurs standard) possède les objets à l'intérieur.
Il est donc responsable de les détruire.

Remarque: Si vous vectoriel contient des pointeurs, alors il possède les pointeurs (pas à quoi pointent les pointeurs). Donc, ceux-ci doivent être supprimés. Mais il y a des moyens plus faciles.

Vous pouvez utiliser un vecteur de pointeurs intelligents. En fait, vous devriez utiliser une forme de pointeur intelligent pour presque tout.Si vous utilisez des pointeurs, vous êtes probablement encore en train de programmer comme un programmeur C.

Alors:

std::vector<int> data; // clear is fine. 

std::vector<int*> data1; // Now things need to be deleted. 
// alternative 1: 
std::vector<boost::shared_ptr<int> > data2; // The shared pointer will auto 
              // delete the pointer. 
// alternative 2: 
boost::ptr_vector<int> data3;    // Here the container knows that 
              // it is holding pointers and will 
              // auto de-reference them when you 
              // its members. 

Mais il semble que vous devez commencer à penser à l'apprentissage de pointeurs intelligents.

int* x = new int(5); 
// Do stuff. 
*x = 8; 
delete x; 

// --- Instead use a smart pointer: 
std::auto_ptr<int> x(new int(5)); 
// Do stuff. 
*x = 8; 
// No delete (the auto ptr handles it. 
5

éléments Suppression de conteneurs STL est garantie pour appeler sur ces éléments destructeurs. Cependant, si vous avez un conteneur de type pointer-to-T, vous devez libérer la mémoire pointée vous-même (dans ce cas, le "destructeur" du pointeur est appelé, ce qui est une non-opération). Si vous ne voulez pas gérer manuellement la mémoire dans ce cas, pensez à utiliser un smart-pointer solution ou un pointer container.

7

Vous n'avez pas besoin de faire cela. std :: string se nettoie, donc les chaînes ne sont pas votre problème. Rappelez-vous que vous n'avez pas utilisé new donc vous n'avez pas besoin d'utiliser delete.

Vous devriez probablement en savoir plus sur RAII - cela simplifie grandement l'allocation et la désallocation. Vous éviterez ainsi les fuites de mémoire.

1

Si vous avez un vecteur et qu'il est hors de portée, tous les objets du vecteur sont détruits. Il n'est pas vraiment nécessaire d'appeler clear() sauf si vous voulez vider le contenu et réutiliser le vecteur.

Cependant, si vous utilisez quelque chose comme un vecteur, le destructeur des objets pointés ne sera pas appelé car le destructeur de vecteurs ne suit pas les indirections représentées par les pointeurs. Cela dit, avez-vous confirmé que vous avez des fuites de mémoire et qu'elles sont causées par les données du vecteur?

0

Comme rlbond suggéré, utiliser RAII.

C'est une bonne règle de ne jamais mettre de nouveaux appels et de supprimer des appels dans votre flux de code principal. Essayez toujours de les placer dans des objets afin que le destructeur d'objets puisse libérer ce qui doit être libéré. De cette façon, vous évitez d'avoir à rappeler d'appeler delete et cela rend votre exception de code sûre (en supposant que vous sauvegardez l'exception d'opérations de votre objet). Par exemple, si vous avez un vecteur de pointeurs sur des chaînes STL ou des tableaux de caractères de style C, placez-le dans un StringContainer (utilisez un meilleur nom) et ayez le StringContainer contenant un vecteur et dans le StringContainer destructor boucle pour supprimer chaque chaîne dans le vecteur. Vous pouvez faire du vecteur dans le StringContainer un membre public et le déranger directement, mais il est encore mieux de le rendre privé ou protégé et d'ajouter quelques fonctions membres pour gérer le string * vector. Donc, votre programme C++ principal ne devrait jamais voir un nouveau ou supprimer n'importe où. Au lieu de cela, il devrait avoir beaucoup d'objets alloués par pile, auto_ptrs et shared_ptrs.

Questions connexes