2009-06-14 9 views
15

Ho imparato dolorosamente negli ultimi giorni molto sulla programmazione in C++.

So che dovrei rilasciare memoria: le regole "ogni malloc = free" o "each new = delete" esistono ora nel mio mondo, ma le sto utilizzando per oggetti piuttosto semplici.
E il vettore? Ovunque posso, sto usando vector.clear() ma questo chiaramente non è abbastanza, perché sto avendo enormi perdite di memoria.
Potresti guidarmi su come dovrei trattare questa cosa?Devo cancellare il vettore <string>?

* Modifica
Grazie, i tuoi commenti mi hanno fatto pensare all'algoritmo di questa applicazione e sarò in grado di eliminare totalmente il vettore. : O
Scusa - Ho iniziato a spiegare quale è il mio caso d'uso qui e ho scoperto di cosa ho veramente bisogno. È così quando si codifica ultimi 3 giorni per 18 ore al giorno: | * Modifica 2
Questo è pazzesco. Con piccole modifiche al codice, ho eliminato l'utilizzo della memoria da 2x130 mb (in costante crescita) in 2x 13,5 mb, dimensione costante. Grazie per avermi fatto riflettere in un altro modo.

Btw. tale revisione del codice ha un nome - qualcuno lo ricorda? È quando chiedi a qualcuno (anche a tua madre o al tuo cane) e inizia a spiegare qual è il tuo problema - e all'improvviso risolvi questo problema di 5 ore te stesso, solo cercando di guardarlo da un altro punto di vista, o semplicemente cercando di riassumere ciò che è tutto su. Mi capita spesso di essere catturato da questo ...

+5

Dal momento che sei nuovo nella gestione della memoria, forse potresti spiegare come sai che stai ricevendo perdite di memoria. Alcuni modi per misurare le perdite di memoria non riflettono realmente ciò che sta accadendo. –

+0

Si potrebbe voler postare alcuni esempi di codice di come si utilizza la classe vettoriale. Ad esempio, hai i vettori di puntatori agli oggetti creati dinamicamente? –

+0

beh, vedo semplicemente che l'esecuzione della mia applicazione comporta un numero sempre maggiore di memoria occupata. Sto eseguendo operazioni abbastanza semplici (facendo gli hash MD5 in 2 processi, legati con mpcih2), per il mio test sono esattamente 25 milioni di operazioni. Un processo invia agli altri pacchetti di dati (stringhe) e il secondo calcola gli hash per quello. Alla fine dell'esecuzione ho 2x 130 mb presi. È troppo per essere normale. – IamDeveloper

risposta

19

La regola è che quando si cancella un vettore di oggetti, verrà chiamato il distruttore di ciascun elemento. D'altra parte, se si dispone di un vettore di puntatori, vector::clear() non chiamerà delete su di essi e sarà necessario eliminarli manualmente.

Quindi, se tutto ciò che si ha è un vettore di stringhe e non di puntatori a stringhe, le perdite di memoria devono essere causate da qualcos'altro.

+0

Questo si applica in generale? Se ho una classe che ha 'std: vector' come una delle sue proprietà, C++ chiamerà quel distruttore quando la classe viene distrutta? –

+4

Sì. Quando un oggetto viene distrutto, viene chiamato il distruttore di tutti i suoi membri di dati. Ma come ho detto, sii consapevole di ciò che stai memorizzando nel vettore. Se è un vettore di oggetti, gli oggetti verranno distrutti insieme al vettore. Se è un vettore di puntatori, devi eliminarli tu stesso. – Dima

7

La chiamata a v.clear() distruggerà tutti gli oggetti attualmente trattenuti all'interno di v, ma non rilascerà la memoria (si presume che il vettore sarà presto riempito di nuovo).

Se davvero si vuole liberare la memoria, il linguaggio è

vector<string>().swap(v); 

questo creerà un nuovo vettore (temporanea) e scambiare il suo contenuto con v. Il vettore temporaneo viene quindi distrutto, liberando la memoria insieme ad esso.

+0

Ora vedo l'intenzione dietro a questo, ma mi sembra abbastanza imbarazzante. E sarebbe lo stesso di v.swap (vector ())? – ypnos

+2

Può sembrare strano, ma è il modo idiomatico di diminuire 'v.capacity()'. Lo snippet non verrà compilato, poiché 'vector ()' è un valore rvalue e non può essere associato a un riferimento non const. – avakar

+0

Per chiarire: in a.swap (b), aeb non sono uguali. Lo scambio membri ha un argomento, un riferimento non const. È possibile chiamare funzioni temporanee di membri non const, quindi in a.swap (b), a può essere temporaneo. Ma b è legato a un riferimento non const e non può essere temporaneo. – MSalters

4

Il vettore (come tutti i contenitori standard) possiede gli oggetti al suo interno.
Quindi è responsabile della loro distruzione.

Nota: se il vettore contiene puntatori, possiede i puntatori (non ciò a cui puntano i puntatori). Quindi questi devono essere cancellati. Ma ci sono modi più semplici.

È possibile utilizzare un vettore di puntatori intelligenti. In realtà dovresti usare qualche forma di puntatore intelligente per quasi tutto.Se stai usando i puntatori probabilmente stai ancora programmando come un programmatore C.

Quindi:

std::vector<int> data; // clear is fine. 

std::vector<int*> data1; // Now things need to be deleted. 
// alternative 1: 
std::vector<boost::shared_ptr<int> > data2; // The shared pointer will auto 
              // delete the pointer. 
// alternative 2: 
boost::ptr_vector<int> data3;    // Here the container knows that 
              // it is holding pointers and will 
              // auto de-reference them when you 
              // its members. 

Ma sembra che è necessario iniziare a pensare a conoscere puntatori intelligenti.

5

L'eliminazione di elementi dai contenitori STL è garantita per chiamare i distruttori su questi elementi. Tuttavia, se si dispone di un contenitore di tipo pointer-to-T, è comunque necessario liberare la memoria puntata (in questo caso viene chiamato il "distruttore" per il puntatore, che è una non operazione).

Se non si desidera gestire manualmente la memoria in questo caso, prendere in considerazione l'utilizzo di smart-pointer solution o pointer container.

7

Non è necessario farlo. std :: string si ripulisce da solo, quindi le stringhe non sono il tuo problema. Ricorda che non hai utilizzato new in modo da non dover utilizzare delete.

Probabilmente dovresti conoscere RAII - rende l'allocazione e la deallocazione molto più semplici. Eviterete perdite di memoria in questo modo.

1

Se si dispone di un vettore e esso non rientra nell'ambito, tutti gli oggetti nel vettore vengono distrutti. Non c'è davvero bisogno di chiamare clear() a meno che non si voglia scaricare i contenuti e riutilizzare il vettore.

Tuttavia, se per caso si utilizza qualcosa come un vettore, il distruttore degli oggetti puntati non verrà chiamato poiché il distruttore vettoriale non segue le indirette rappresentate dai puntatori.

Tutto ciò detto, hai effettivamente confermato che hai perdite di memoria e che sono causate dai dati nel vettore?

0

Come suggerito, utilizzare RAII.

È una buona regola empirica non inserire mai nuove e cancellare chiamate nel flusso di codice principale. Cerca sempre di metterli in oggetti in modo che il distruttore di oggetti possa liberare ciò che deve essere liberato. In questo modo, eviti di dover ricordare di chiamare delete e questo rende il codice eccezionalmente sicuro (assumendo che tu faccia in modo che le operazioni del tuo oggetto siano eccezionalmente sicure).

Ad esempio, se si dispone di un vettore di puntatori a stringhe STL o array di caratteri stile C, inserirlo in un StringContainer (utilizzare un nome migliore) e tenere Stringcontainer in possesso di un vettore e nel distruttore StringContainer eseguire a loop per cancellare ogni stringa nel vettore.

È possibile rendere il vettore all'interno di StringContainer un membro pubblico e aggirarlo con esso direttamente, ma è ancora meglio progettarlo per renderlo privato o protetto e aggiungere alcune funzioni membro per gestire il vettore stringa *.

Quindi il tuo programma C++ principale non dovrebbe mai vedere un nuovo o eliminare da nessuna parte. Invece dovrebbe avere un sacco di oggetti allocati nello stack, auto_ptrs e shared_ptrs.

Problemi correlati