2010-10-31 4 views
18

J'ai un vecteur que je remplis de pointeurs vers des objets. J'essaie d'apprendre la bonne gestion de la mémoire, et j'ai quelques questions générales:Que dois-je faire avant de supprimer des éléments dans un vecteur de pointeurs vers des objets alloués dynamiquement?

  1. Est-il vrai que lorsque j'en ai fini avec le vecteur, je dois faire une boucle et appeler supprimer sur chaque pointeur? Pourquoi ne dois-je pas appeler delete sur le vecteur ou toute autre variable que je déclare sans la nouvelle instruction, mais delete doit être appelé sur des pointeurs?
  2. C++ gère-t-il la libération de la mémoire des pointeurs si le vecteur est déclaré dans une fonction qui retourne (provoquant la sortie du vecteur)?

Répondre

21
  1. Oui
  2. Les vecteurs sont mis en œuvre à l'aide de mémoire allocateurs modèle qui prennent en charge la gestion de la mémoire pour vous, ils sont donc un peu particulier. Mais en règle générale, vous n'avez pas besoin d'appeler delete sur les variables qui ne sont pas déclarées avec le mot-clé new en raison de la différence entre la pile et l'allocation de tas. Si des éléments sont alloués sur le tas, ils doivent être supprimés (libérés) pour éviter les fuites de mémoire.
  3. Non. Vous devez explicitement appeler delete myVec[index] lorsque vous parcourez tous les éléments.

Ex:

for(int i = 0; i < myVec.size(); ++i) 
    delete myVec[i]; 

Cela dit, si vous avez l'intention de stocker des pointeurs dans un vecteur, je vous suggère fortement d'utiliser boost::ptr_vector qui prend automatiquement en charge la suppression.

+1

3: C++ libérera bien sûr la mémoire utilisée par les pointeurs, puisqu'ils sont alloués sur la pile. Mais les objets pointés par ces pointeurs sont très probablement alloués sur le tas et devront donc être supprimés. Et bien sûr, les pointeurs dans le vecteur pourraient pointer vers des objets alloués par pile, qui ne peuvent pas être supprimés. En règle générale, vous ne devez jamais stocker de pointeurs non const pour empiler des objets alloués dans un vecteur. – smerlin

+1

Merci! C'était très clair! –

2

Vous pouvez également utiliser std :: unique_ptr si vous avez accès à C++ 0x. Il remplace l'obsolète std :: auto_ptr qui n'a pas pu être utilisé dans les conteneurs. Tout ce que vous allouez avec new vous devez delete plus tard sur

2

Les objets que vous n'allouez pas explicitement avec new ne devraient pas vous delete.

Si vous ne voulez pas gérer les objets manuellement mais que vous voulez que le vecteur les "possède", il peut être préférable de stocker les objets par valeur au lieu de les stocker avec des pointeurs. Donc, au lieu de std::vector<SomeClass*>, vous pouvez utiliser std::vector<SomeClass>.

10

Est-il vrai que lorsque j'en ai fini avec le vecteur, je dois le faire défiler et appeler la suppression sur chaque pointeur?

Eh bien, vous ne devez pas en boucle à la main, vous pouvez également utiliser un algorithme:

#include <vector> 
#include <algorithm> 
#include <memory> 

int main() 
{ 
    std::vector<Base*> vec; 
    vec.push_back(new Derived()); 
    vec.push_back(new Derived()); 
    vec.push_back(new Derived()); 

    // ... 

    std::for_each(vec.begin(), vec.end(), std::default_delete<Base>()); 
} 

Si vous ne disposez pas d'un compilateur C++ 0x, vous pouvez utiliser boost:

#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/construct.hpp> 

std::for_each(vec.begin(), vec.end(), boost::lambda::delete_ptr()); 

Ou vous pouvez écrire votre propre foncteur:

struct delete_ptr 
{ 
    template <class T> 
    void operator()(T* p) 
    { 
     delete p; 
    } 
}; 

std::for_each(vec.begin(), vec.end(), delete_ptr()); 
2

Comme alternative à boost::ptr_vector comme mentionné par David Titarenco, vous pouvez facilement modifier std :: vecteur pour libérer la mémoire automatiquement pour contenir des pointeurs sur la suppression:

template<class T> 
class Group : public std::vector<T> 
{ 
public: 
    virtual ~Group() {}; 
}; 

template<class T> 
class Group<T *> : public std::vector<T *> 
{ 
public: 
    virtual ~Group() 
    { 
     std::vector<T *>::reverse_iterator it; 
     for (it = this->rbegin(); it != this->rend(); ++it) 
      delete *it; 
    } 
}; 

Toutes les fonctionnalités fournies par std :: vecteur est hérité si vous ajouter des éléments de la même façon :

Group<Foo *> *bar = new Group<Foo *>(); 
bar->push_back(new Foo()); 
bar->push_back(new DerivedFoo()); 

// Deleting the Group will free all memory allocated by contained pointers 
delete bar; 
Questions connexes