2010-12-15 19 views

risposta

16

Se viene sollevata un'eccezione tra l'allocazione e la deallocazione, si verifica perdita di memoria.

void f1() { 
    int* ptr = new int; 

    // do something which may throw an exception 

    // we never get here if an exception is thrown 
    delete ptr; 
} 

Ogni volta f1 termina con un'eccezione, 4 byte si perdono (supponendo int è 4 byte).

+0

great point grazie watson – ashmish2

+3

... uno dei motivi per cui i puntatori intelligenti sono "più intelligenti" dei puntatori grezzi come "int *" (che non hanno distruttori): http://stackoverflow.com/questions/106508/what-is -a-smart-pointer-and-when-should-i-use-one – HostileFork

13

Una perdita di memoria è causata quando la memoria allocata, non hanno ma lo hai deallocato, e non sarai mai in grado di deallocarlo perché non puoi più accedervi.

Ad esempio, il seguente codice provoca una perdita di memoria di dimensioni sizeof(int):

int * a = malloc(sizeof(int)); //allocate memory 
a = 0; //this will cause a memory leak 

Questo crea una perdita di memoria, perché ora non saremo mai in grado di rilasciare la memoria allocata per a.

2

Un new senza un delete, un new[] senza delete[], un malloc senza free.

Seriamente, che altro vuoi sentire?

6

È inoltre possibile perdere memoria quando non si rilascia una qualche altra risorsa come non chiamare fclose su un FILE * o un altro handle di libreria poiché possono allocare buffer di memoria che non sono direttamente accessibili per il programma.

2

Non c'è altra ragione per la perdita di memoria oltre a quello si parla

+0

Un controesempio a questa è la risposta di watson1180. – Cam

+0

@Cam: Non penso, nell'esempio di watson1180, ha dimenticato di chiamare 'delete' (anche se è scritto nel codice). –

+0

@Matthieu: Hmm ... anzi. Purtroppo non sono attualmente in grado di annullare la risposta di beb0. – Cam

4

Supponiamo di aver creato una classe che eredita un'altra classe che non ha un distruttore virtuale. Se il tipo di puntatore a questa classe non è la classe più derivata (questo di solito accade se si utilizza una fabbrica astratta) verrà chiamato solo il distruttore dal tipo del puntatore e tutto ciò che si sperava avrebbe reso libero nel più derivato il distruttore di classe perderà.

Questo è un errore molto comune e uno che a volte è difficile da vedere.

In ogni caso, se si vuole evitare perdite di memoria con C++ seguire queste regole:

  • Preferisco passare riferimenti piuttosto che puntatori
  • Usa puntatore intelligente quando possibile (vedi: shared_ptr)
+0

ovviamente, lo standard dice che è un comportamento indefinito se il distruttore della classe base non è virtuale, quindi stai manomettendo il male e una perdita di memoria è l'ultima delle tue preoccupazioni qui. Per quanto riguarda 'shared_ptr', a volte è utile, ma ci sono dei puntatori/contenitori intelligenti molto migliori per l'uso quotidiano. Certamente dovrebbe essere l'ultima scelta. –

0

Sono sorpreso che nessuno abbia menzionato la corruzione della memoria ancora.

Ricordo un caso in cui si disponeva di un grezzo allocatore di memoria a blocchi di dimensioni fisse implementato come elenco collegato.

Qualcuno aveva incasinato calcoli di dimensioni, portando a copiare i dati solo un paio di byte oltre la dimensione massima del blocco (i puntatori erano solo 2 byte lunghi al momento :)). Sovrascriverebbe quindi il collegamento "successivo" situato all'inizio del prossimo blocco libero con la spazzatura che è stata riempita di zeri.

Ciò ha avuto la conseguenza di interrompere la catena di blocchi liberi. Dal momento che a quel punto gli altri software hanno mantenuto i loro puntatori a qualunque blocco stessero usando, il programma sembrava funzionare bene.

Ma ovviamente la lista non era sufficiente per pochi isolati una volta ogni tanto, e questa perdita alla fine ha esaurito i blocchi liberi, facendo morire di fame l'applicazione.

0

L'esempio seguente, scritto in pseudocodice, ha lo scopo di mostrare come si può verificare una perdita di memoria e i suoi effetti, senza bisogno di alcuna conoscenza di programmazione. Il programma in questo caso fa parte di un software molto semplice progettato per controllare un ascensore. Questa parte del programma viene eseguita ogni volta che qualcuno all'interno dell'ascensore preme il pulsante per un piano.

Quando si preme un pulsante:

Get some memory, which will be used to remember the floor number 
    Put the floor number into the memory 
    Are we already on the target floor? 
    If so, we have nothing to do: finished 
    Otherwise: 
     Wait until the lift is idle 
     Go to the required floor 
     Release the memory we used to remember the floor number 

La perdita di memoria si verifica se il numero del piano richiesto è lo stesso piano che l'ascensore è acceso; la condizione per il rilascio della memoria sarebbe saltata. Ogni volta che si verifica questo caso, viene perduta più memoria.