2010-10-31 10 views
18

Ho un vettore che riempio con i puntatori agli oggetti. Sto cercando di imparare una buona gestione della memoria, e ho alcune domande generali:Cosa devo fare prima di eliminare elementi in un vettore di puntatori agli oggetti allocati dinamicamente?

  1. E 'vero che quando mi sono fatto con il vettore, devo ciclo attraverso di essa e chiamare cancellare su ogni puntatore?
  2. Perché non devo chiamare delete sul vettore o qualsiasi altra variabile che dichiaro senza la nuova istruzione, ma cancellare deve essere chiamato sui puntatori?
  3. Il C++ gestisce la liberazione della memoria dei puntatori per me se il vettore viene dichiarato in una funzione che restituisce (facendo sì che il vettore non rientri nello scope)?

risposta

21
  1. vettori sono realizzati tramite allocatori memoria modello che si prendono cura della gestione della memoria per voi, in modo che siano un po 'speciale. Tuttavia, come regola generale, non è necessario chiamare delete su variabili che non sono dichiarate con la parola chiave new a causa della differenza tra l'allocazione stack e heap. Se roba è allocata nell'heap, deve essere cancellata (liberata) per evitare perdite di memoria.
  2. No. È necessario chiamare esplicitamente delete myVec[index] mentre si esegue l'iterazione su tutti gli elementi.

Es:

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

Detto questo, se avete intenzione di memorizzare i puntatori in un vettore, vi consiglio vivamente di utilizzare boost::ptr_vector che si occupa automaticamente della delezione.

+1

3: C++ libererà naturalmente la memoria utilizzata dai puntatori, poiché sono allocati nello stack. Ma gli oggetti puntati da quei puntatori sono probabilmente allocati sull'heap e quindi dovranno essere cancellati. E naturalmente i puntatori nel vettore potrebbero puntare a impilare oggetti allocati, che potrebbero non essere cancellati. In genere non si dovrebbero mai memorizzare puntatori non-const per impilare oggetti allocati in un vettore. – smerlin

+1

Grazie! E 'stato molto chiaro! –

2

È anche possibile utilizzare std :: unique_ptr se si ha accesso a C++ 0x. Sostituisce il deprecato std :: auto_ptr che non può essere utilizzato nei contenitori.

2

Tutto ciò che si assegna con new è necessario delete in seguito. Gli oggetti che non si assegnano esplicitamente con new non dovrebbero essere delete.

Se non si desidera gestire manualmente gli oggetti ma si desidera che il vettore li "li possegga", potrebbe essere preferibile archiviare gli oggetti in base al valore anziché archiviarvi i puntatori. Quindi invece di std::vector<SomeClass*> potresti usare std::vector<SomeClass>.

10

È vero che quando ho finito con il vettore devo passarlo attraverso e chiamare cancellare su ogni puntatore?

Beh, non c'è bisogno di ciclo a mano, è anche possibile utilizzare un algoritmo:

#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>()); 
} 

Se non si dispone di un compilatore C++ 0x, è possibile utilizzare spinta:

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

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

Oppure si può scrivere il proprio funtore:

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

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

In alternativa a boost::ptr_vector come detto da David Titarenco, si può facilmente modificare std :: vector in memoria automaticamente libero per contenente indicazioni su cancellazione:

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; 
    } 
}; 

Tutte le funzionalità fornite da std :: vector è ereditato in modo che avrebbe aggiungere elementi allo stesso modo :

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; 
Problemi correlati