2010-09-17 4 views
5

Dovremmo eliminare prima o dopo erase. La mia comprensione è che entrambi stanno bene. È corretto?Dovremmo cancellare prima o dopo la cancellazione di un puntatore nel vettore?

Inoltre, è possibile che non si voglia eliminare l'elemento durante la cancellazione? Credo che ci deve essere, altrimenti, il erase sarà felice di assumersi la responsabilità.

std::vector<foo*> bar; 
... 
for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end(); itr++) 
{ 
    delete (*itr); //before OR 
    bar.erase(itr); 
    delete (*itr); //after??? 
} 
+0

intendi 'std :: vector ' – sellibitze

+0

grazie. corretto. – pierrotlefou

+0

Credo che tu abbia anche 'iter ++', altrimenti il ​​ciclo non terminerà. – Naveen

risposta

10

"itr" deve essere utilizzato in questo modo;

Tuttavia, preferisco prima cancellare tutti gli elementi e quindi cancellare il vettore;

for (vector<foo*>::iterator itr = bar.begin(); itr != bar.end(); ++itr) 
    delete (*itr); 
bar.clear(); 
+1

+1, opterei anche per la seconda versione: in questo modo non avrei tutti quegli spostamenti di elementi all'interno del vettore. Per lo meno se si utilizza un ciclo con cancellazione, l'iterazione all'indietro sarebbe più adatta. –

+0

Sono d'accordo, ma non sono sicuro che vector :: erase sia compatibile con un reverse_iterator (stanco di pensarlo) –

+0

Dovresti utilizzare la soluzione preferita. È ** O (n) ** in contrapposizione a ** O (n^2) **. – kevlar

4

L'utilizzo di un iteratore per cancellare un elemento invalida l'iteratore. Dovresti cancellare l'oggetto prima che venga cancellato.

Si dovrebbe anche usare il valore di ritorno da cancellare per la successiva iterazione del ciclo.

+0

buoni commenti in generale, ma puoi dirci qual è la ragione alla base di "Devi eliminare l'elemento prima che venga cancellato". Non vedo perché questo dovrebbe essere il caso. In effetti, penserei che il contrario sarebbe più sicuro (cioè nel codice multithread). Lo svantaggio è che devi mantenere il valore del puntatore in modo temporaneo prima di chiamare cancella o non sarai in grado di eliminarlo. Non lo vedo fornire un grande vantaggio, quindi non lo consiglierei ma il tuo modo formulato la tua risposta sembra cancellare prima è l'unico modo. – n1ckp

+0

@ n1ck: stava chiedendo tra due varianti (vale a dire prima o dopo). Stavo semplicemente affrontando la domanda. Ovviamente è possibile spostare il puntatore su un valore temporaneo, ma eliminarlo in posizione funziona altrettanto bene per la maggior parte delle applicazioni. – Paul

+0

Harvey: certo, ho appena detto che la tua formulazione forse non è la migliore, perché sembra implicare che sia l'unico modo. Penso che il lettore dovrebbe essere in grado di capire, ma volevo solo essere totalmente chiaro, questo è tutto. – n1ckp

1

Fare un erase invaliderà l'iteratore vector. Pertanto, *iter invocherà un comportamento non definito. Quindi è necessario fare il delete dopo il erase. Inoltre, non è possibile erase gli elementi da un vector durante l'iterazione attraverso di esso (a causa dello stesso motivo, iter non è valido, quindi iter++ non è valido). In questo caso è possibile rimuovere la chiamata erase dall'interno del loop e fare clear del vettore all'esterno del ciclo.

2

La natura del vettore che cancellare primo elemento provoca intera matrice di spostare in avanti, per ridurre questa operazione prova seguente:

std::vector<foo*> v1; 
//... 
while(!v1.empty()) 
{ 
    delete v1.back(); 
    v1.pop_back(); 
} 

proposito - questo metodo non inficia alcuna iteratori (solo sugli articoli cancellati)

3

Inoltre, è possibile che non si voglia eliminare l'elemento durante la cancellazione?

Come potrebbe il vettore sapere se qualcun altro ha bisogno degli oggetti puntati? Come potrebbe anche sapere che le punte sono immagazzinate sul mucchio? È perfettamente possibile avere puntatori a oggetti statici o automatici nel vettore, o anche puntatori penzolanti.

C++ 0x consente di esprimere che il vettore dovrebbe possedere le pointees:

std::vector<std::unique_ptr<foo>> vec; 

Ora non c'è bisogno di eliminare manualmente qualsiasi cosa. Cancellando i puntatori unici, anche le loro rispettive punte vengono cancellate. I contenitori di puntatori nativi sono molto rari nel moderno C++.

Se non si dispone di un compilatore C++ 0x, è possibile utilizzare std::vector<boost::shared_ptr<foo> > o boost::ptr_vector<foo>. I compilatori moderni forniscono shared_ptr nello spazio std::tr1 o std anche se si è #include <memory>.