Diversamente dalla memoria locale sullo stack,
la memoria del heap deve essere semplicemente liberata. Un
volta conclusa l'operazione con il blocco di memoria allocato con
l'operatore new, deve essere liberato con l'operatore delete.
Questo è ciò che viene fatto nel programma con il blocco di memoria
heap che ha immagazzinato 20.
delete
pHeap;
La memoria viene restituita a heap per uso futuro. I
dati che sono stati immagazzinati non sono più disponibili. Nella
riga seguente viene liberata anche la memoria di pHeap2. Un
importante argomento da comprendere è che le due istruzioni liberano
la memoria su heap ma non interagiscono sulle variabili locali
pHeap e pHeap2. Questo crea un potenziale problema in quanto i
puntatori segnano una locazione che può essere assegnata dal
computer a qualsiasi altra operazione. Questi puntatori sono chiamati
puntatori appesi e sono da
evitare. Una via per
gestire i puntatori appesi è di assegnare valore 0 a loro, il quel
viene fatto nel programma con le seguenti istruzioni.
pHeap
=0;
pHeap2 =0;
Un altro metodo per
gestirli è di assegnare loro un indirizzo valido di memoria.
Evitare perdite di memoria
Un problema che il programmatore deve evitare è di
allocare memoria e perdere la possibilità di gestirla in qualche
modo per poterla liberare in seguito. Quando la memoria viene persa
questo è chiamato memory leak.
In un programma di grandi dimensioni questo può comportare un vasto
problema sino a provocare il crash del sistema. Come programmatore è
necessario evitare le perdite di memoria. Nel programma Heap sono
state inserite due funzioni le quali creano perdite di memoria, come
esempio, in modo da mostrare come non gestire la memoria dinamica in
un programma. Nella prima funzione perdita1(), viene allocato un
blocco di memoria per un valore intero e quindi si conclude.
void
perdita1()
{
int* dripeti1 = new int(40); }
Se viene chiamata
questa funzione, la memoria viene persa per sempre durante il
funzionamento del programma. Il problema è che dripeti1,
è il solo collegamento con il blocco appena acquisito di memoria su
heap, quando la
variabile locale cessa di esistere, la funzione perdita1() si
conclude. Così non esiste un modo per accedere alla memoria
allocata. Per evitare questa perdita di memoria si possono fare due
cose, usare l'istruzione delete per liberare la memoria o restituire
una copia di dripeti1, e liberare la memoria in un'altra parte del
programma.
La seconda funzione
creata è perdita2().
void
perdita2()
{
int* dripeti2 = new int(50);
dripeti2 = new int(200);
delete dripeti2;
}
In questo caso la
perdita di memoria è più sottile, ma esiste comunque. La prima
linea della funzione, alloca un blocco di memoria su heap
al quale assegna un valore di 50, e dripeti2
punta ad esso. Tuttavia nella seconda istruzione viene, a dripeti2,
assegnato un nuovo blocco di memoria al quale viene attribuito valore
200. Infine si cancella il contenuto del blocco di memoria dripeti2.
Il problema è che il blocco al quale era stato assegnato valore 50
non ha più alcun puntatore che fa riferimento ad esso e pertanto non
può essere liberato. Questo è un altro esempio di perdita di
memoria del programma. In questo caso dripeti2
è un puntatore appeso, ma del quale non bisogna preoccuparsi in
quanto cessa di esistere al termine della funzione.