Page 1 of 1

[C++] Cum eliberez memorie pentru un sir de poineri?

Posted: 25 Jul 2007, 15:57
by Marius Bancila
Intrebare: Cum eliberez memorie pentru un sir de poineri?

Raspuns: Pentru a da raspunsul, sa plecam de la urmatorul cod:

Code: Select all

byte rows = 3;
byte cols = 3;
byte **array = new byte*[rows];

for(int i=0; i < rows; i++)
{
  array[i] = new byte[i+1];
}

delete [] array;
Acest cod genereaza memory leak-uri, intrucat nu toata memoria alocata a fost eliberata. In codul anterior, array este un sir de pointeri, si fiecare pointer indica spre un alt bloc de memorie, alocat separat. Inainte de a elibera memoria pentru array, trebuie eliberate blocurile pointate de elementele sale.

In linia:

Code: Select all

byte **array = new byte*[rows];
se aloca memorie pentru 3 elemente (rows e 3). Variabila array se afla pe stiva, si indica catre un bloc de memorie de pe heap. Daca folositi debugger-ul se poate vedea valoarea acestei variabile, adica adresa de start a memorie pe heap. In cazul meu vad in debugger 0x009A4AD0.

Code: Select all

009A4ACC  FD FD FD FD
009A4AD0  CD CD CD CD
009A4AD4  CD CD CD CD
009A4AD8  CD CD CD CD
009A4ADC  FD FD FD FD
Acele FD-uri incadreaza o zona de pe heap, alocata dinamic. (Mai multe se pot citi aici: Inside CRT: Debug Heap Management.)

In acest moment elementele lui array nu sunt initializate, si de aceea intr-o configuratie de debug au valoarea CDCDCDCD (citeste articolul anterior pentru mai multe). Dupa prima interatie, se aloca un nou bloc de memorie pe heap, iar adresa sa este pastrata in array[0].

Code: Select all

009A4ACC  FD FD FD FD
009A4AD0  18 4B 9A 00
009A4AD4  CD CD CD CD
009A4AD8  CD CD CD CD
009A4ADC  FD FD FD FD 
Blocul de memorie indicat de acest array[0] arata cam asa:

Code: Select all

009A4B14  FD FD FD FD
009A4B18  CD FD FD FD
009A4B1C  FD F0 AD BA
El contine un singur byte, incadrat de octetii FD (intr-o build de debug).

In mod asemanator se inampla lucrurile dupa a 2-a, respectiv a 3-a iteratie. In final ajungem la

Code: Select all

009A4ACC  FD FD FD FD
009A4AD0  18 4B 9A 00
009A4AD4  60 4B 9A 00
009A4AD8  A8 4B 9A 00
009A4ADC  FD FD FD FD
Atentie: aceste adrese pot depinde de la un rulare la alta.

Prin urmare, in total se aloca 1+2+3 = 6 octeti de memorie plus memoria necesara pentru a tine pointerii catre aceste 3 bloc-uri, adica inca 3*4 = 12 octeti. Atunci cand scrieti asta:

Code: Select all

delete [] array;
Nu faceti decat sa eliberati memoria alocata pentru array, dar nu si blocurile catre care elementele sale pointeaza. Daca rulati in debugger veti vedea asta in fereastra de output la sfarsitul executiei:
Detected memory leaks!
Dumping objects ->
D:\Teste\test.cpp(104) : {65} normal block at 0x009A4BA8, 3 bytes long.
Data: < > CD CD CD
D:\Teste\test.cpp (104) : {64} normal block at 0x009A4B60, 2 bytes long.
Data: < > CD CD
D:\Teste\test.cpp (104) : {63} normal block at 0x009A4B18, 1 bytes long.
Data: < > CD
Object dump complete.
Pentru a dezaloca corect, trebuie facut asa:

Code: Select all

for(i=0; i < rows; i++)
{
  delete [] array[i];
}

delete [] array;
Imaginea de mai jos explica grafic relatia dintre pointeri si blocurile de memorie.
array.gif
o reprezentare grafica a blocurilor de memorie
array.gif (4.67 KiB) Viewed 4455 times