Domanda Std :: vector.clear () cancella (memoria libera) su ogni elemento?


Considera questo codice:

#include <vector>

void Example()
{
    std::vector<TCHAR*> list;
    TCHAR* pLine = new TCHAR[20];
    list.push_back(pLine);
    list.clear();    // is delete called here?
    // is delete pLine; necessary?
}

List.clear () chiama delete su ogni elemento? Cioè devo liberare la memoria prima / dopo list.clear ()?


57
2018-02-27 09:26


origine


risposte:


No (devi eliminare tu stesso alla fine mentre suggerisci nel tuo esempio come la distruzione del puntatore calvo non fa nulla). Ma puoi usare un puntatore intelligente di potenziamento [o altro idioma basato su RAII] per farlo fare la cosa giusta (auto_ptr non funzionerebbe correttamente in un contenitore in quanto ha un comportamento incompatibile durante la copia, ecc.), ma assicurati di comprendere le insidie ​​di tali indicatori intelligenti prima dell'uso. (Come menziona Benoit, in questo caso, basic_string è quello che stai davvero cercando qui.)

Detto questo, c'è bisogno di capire le insidie ​​dei puntatori intelligenti, avere loro a che fare con la gestione della memoria implicitamente in modo da non doverlo fare esplicitamente è molto meno soggetto a errori.

EDIT: sostanzialmente rivisto per comprendere gli elementi che Benoit ha portato nella sua risposta molto più approfondita, grazie al forte stimolo da parte di Earwicker e James Matta - grazie per avermi spinto a fare la due diligence su questo!


31
2018-02-27 09:28



std :: vector chiama il distruttore di ogni elemento che contiene quando viene chiamato clear (). Nel tuo caso particolare, distrugge il puntatore ma gli oggetti rimangono.

I puntatori intelligenti sono la giusta strada da percorrere, ma attenzione. auto_ptr non può essere usato nei contenitori std. boost :: scoped_ptr non può neanche. boost :: shared_ptr can, ma non funzionerà nel tuo caso perché non hai un puntatore a un oggetto, in realtà stai usando un array. Quindi la soluzione al tuo problema è da usare boost :: shared_array.

Ma ti suggerisco di usare std :: basic_string invece, dove non dovrai occuparti della gestione della memoria, mentre ottieni i benefici di lavorare con una stringa.


48
2018-02-27 09:35



Potresti semplicemente scrivere una semplice funzione template che faccia questo per te:

template <class T>
void deleteInVector(vector<T*>* deleteme) {
    while(!deleteme->empty()) {
        delete deleteme->back();
        deleteme->pop_back();
    }

    delete deleteme;
}

Forse qualcosa qui è una cattiva pratica, ma io non la penso così. Mi sembra a posto anche se i commenti sono sempre belli.


8
2017-11-16 04:47



Ecco un modo in cui puoi dire che non è così: provalo su una classe che non è completamente definita:

#include <vector>
class NotDefined;

void clearVector( std::vector<NotDefined*>& clearme )
{
    clearme.clear();    // is delete called here?
}

Se questo frammento di codice viene compilato, non può chiamare il distruttore, perché il distruttore non è definito.


7
2018-02-27 13:32



No. Non lo fa poiché non vi è alcuna garanzia che non si stia utilizzando il puntatore da nessun'altra parte. Se non fosse una variabile puntatore, li libererebbe (chiamando il distruttore)


5
2018-02-27 09:29



Potresti anche essere in grado di utilizzare il Boost Pointer Container Library. Non specificamente raccomandato qui (di nuovo perché stai usando array invece di singoli oggetti, però std::string si prenderà cura di questo), ma è una libreria utile e poco conosciuta che risolve il problema indicato nel titolo.


0
2018-02-27 18:56