2010-09-14 5 views
5

Come posso liberare memoria in un vettore puntatore? Ecco il codice:Come posso liberare un vettore puntatore?

class A 
{ 
    private: 
     int x,y,z; 
    public: 
     A(param1, param2, param3) 
     { 
      x=param1; 
      y=param2; 
      z=param3; 
     } 
     ~A() 
     { 
      //prompts an alertbox, warning me about the successful call of the destructor; 
     } 
}; 

... 
vector<A*> list; 
list.push_back(new A(1,2,3)); 

list.erase(list.begin()+index);//SHOULD delete the object from the memory; 
list.clear(); 

ho scoperto che .erase() non liberare la memoria, né chiama il distruttore; Ho provato ad usare delete su ogni voce di lista con un'iterazione, ma si blocca dopo una iterazione. Già controllato se la voce della lista fosse già NULL, per evitare qualsiasi errore. Mi manca qualcosa? Inoltre, devo usare solo STL, non serve Boost.

+0

Nota che chiamare 'delete' su un puntatore' NULL' è sicuro. –

+4

Si potrebbe voler usare un 'boost :: ptr_vector' dalla libreria Boost Ptr Container. –

+3

perché usare 'A *' quando normale 'A' farebbe? –

risposta

0
 
for(size_t i = 0; i < list.size(); ++i) 
{ 
    delete list[i]; 
} 

list.clear(); 

Se si fa qualcosa del genere e il codice si blocca, inserire il codice esatto e le informazioni sugli arresti anomali.

+0

L'uso degli iteratori qui sarà più efficiente e indipendente dal contenitore (in futuro potrai passare alla lista senza supporto per l'accesso casuale). –

8

list.erase deallocerà la memoria per i suoi elementi membri (e chiamerà i loro distruttori, se esistono); non chiamerà delete su di loro.

A Boost shared_ptr sarebbe il modo più ovvio per farlo. Se non si desidera utilizzarlo, è possibile scrivere la propria classe smart-pointer, o iterare tramite list e chiamare delete su ciascun puntatore prima di chiamare erase. È possibile farlo ordinatamente con qualcosa di simile:

void my_delete(A *p) 
{ 
    delete p; 
} 

... 

std::for_each(list.begin(), list.end(), my_delete); 
+3

+1: sempre, sempre, usa puntatori intelligenti a meno che tu non sappia davvero cosa stai facendo. – Puppy

+1

@DeadMG, sì mi dica di più sulle dipendenze cicliche con shared_ptr :-) –

+3

@Oli, shared_ptr non è sicuramente il modo ovvio in quanto non vi è alcuna intenzione di condividere effettivamente questi oggetti. std :: unique_ptr da C++ 0x, boost ptr_vector o nel caso peggiore - ptr intrusivo sembra essere una scelta più ovvia. –

4
for(std::vector<A*>::iterator i = list.begin(), endI = list.end(); i != endI; ++i) 
{ 
    delete *i; 
} 
list.clear(); 

o, utilizzando nuove funzioni lambda

std::for_each(list.begin(), list.end(), [](A* element) { delete element; }); 
list.clear(); 
+0

+1 per rispondere alla domanda Il modo in cui si doveva rispondere. – rubenvb

+0

Vorrei che funzionasse ... mi da gli stessi errori di prima. – Tibor

+0

Non so dove può andare in crash, ma sono quasi sicuro che non si trovi nel ciclo for_each. Forse stai accedendo ad alcuni degli oggetti cancellati dopo la distruzione, il che provocherà sicuramente un crash. –

3

erase cancella solo ciò che è nel vettore (i puntatori) senza fare nulla di quello che potrebbe indicare.

Se si desidera il punto eliminato, è necessario gestirlo autonomamente.

Il mio consiglio è di evitare di maneggiare qualsiasi di questo voi stessi, e considerare l'utilizzo Boost ptr_vector invece.

+1

Anche se l'OP ha chiesto di non usare boost, preferisco comunque questa risposta. Programmare in C++ senza Boost è come arrampicarsi con un braccio legato nella parte posteriore: possibile, ma stupido. –

2

Dopo la distruzione, un container STL distruggerà gli oggetti in esso contenuti. Se quegli oggetti sono puntatori, distruggeranno i puntatori. Per i puntatori nudi muti, , questo non eliminerà gli oggetti che puntano a. Ecco perché di solito è meglio usare puntatori intelligenti per questo. I puntatori intelligenti cancellano gli oggetti a cui si riferiscono dopo la cancellazione; std::shared_ptr tiene traccia dei puntatori di copia e quanti riferimenti a un determinato oggetto esistono e eliminerà l'oggetto solo quando l'ultimo puntatore muore. Questo è sempre un buon primo candidato quando si cerca un puntatore intelligente adatto. Il tuo contenitore verrebbe quindi dichiarato come segue: std::vector< std::shared_ptr<A> >

Tuttavia, il tuo compilatore/std lib potrebbe non essere fornito con std::shared_ptr, che è una funzionalità del prossimo standard C++, generalmente previsto il prossimo anno. Potrebbe, tuttavia, porta con std::tr1::shared_ptr, che è una caratteristica TR1 a partire dal 2003. (se tutto il resto fallisce, spinta ha boost_shared_ptr, ma è già escluso spinta.)

You can oggetti manualmente gestire dinamicamente assegnate a STL contenitori, ma è un peso e soggetto a errori. Ad esempio, è necessario impedire alle funzioni di tornare in anticipo (prima della pulizia manuale) tramite le dichiarazioni o le eccezioni return e si deve prestare attenzione alle operazioni di copia sui contenitori.(Altrimenti due contenitori avrebbero puntatori che si riferiscono agli stessi oggetti, che potrebbero quindi provare a distruggere due volte.)
Gestire manualmente le risorse è un PITA, soggetto a errori e meglio evitato.

1

Il codice che hai postato non è C++ legittimo. Inoltre, cancella non cancella gli oggetti che hai assegnato, cancella solo i contenuti del vettore, che nel tuo caso sono puntatori. Gli oggetti reali che hai assegnato non vengono cancellati. Ecco un modo corretto di fare ciò che si vuole:

#include <vector> 
#include <algorithm> 

class A 
{ 
    int x,y,z; 

public: 
    A (int param1, int param2, int param3) : 
     x (param1), y (param2), z (param3) 
    { 
    } 
}; 

struct Deleter 
{ 
    template <typename T> 
    void operator() (T *obj) const 
    { 
     delete obj; 
    } 
}; 

int 
main() 
{ 
    std::vector<A*> list; 

    list.push_back (new A (1, 2, 3)); 
    list.push_back (new A (4, 5, 6)); 
    list.push_back (new A (7, 8, 9)); 

    std::for_each (list.begin(), list.end(), Deleter()); 
    list.clear(); 
} 

Si può anche guardare Boost Ptr Container libreria che risolve questo problema in un modo sicuro e riutilizzabile. In C++ 0x, esiste una classe template std :: unique_ptr che supporta la semantica mobile e può essere utilizzata con contenitori e algoritmi STL per ripulire automaticamente la memoria.