C++/Zarządzanie pamięcią: Różnice pomiędzy wersjami
Nie podano opisu zmian |
poprawki |
||
Linia 3: | Linia 3: | ||
Rozważmy prosty przykład. Załóżmy, że chcemy stworzyć wektor 10 liczb typu całkowitego. Możemy to zrobić na dwa sposoby. W stylu znanym z języka C: |
Rozważmy prosty przykład. Załóżmy, że chcemy stworzyć wektor 10 liczb typu całkowitego. Możemy to zrobić na dwa sposoby. W stylu znanym z języka C: |
||
<source lang="cpp"> |
<source lang="cpp"> |
||
int * |
int *wektor = (int*) malloc (sizeof(int)*10); |
||
free( |
free (wektor); |
||
</source> |
</source> |
||
Albo w stylu C++: |
Albo w stylu C++: |
||
<source lang="cpp"> |
<source lang="cpp"> |
||
int * |
int *wektor = new int[10]; |
||
delete [] |
delete [] wektor; |
||
</source> |
</source> |
||
⚫ | Od razu widać, że drugi zapis jest łatwiejszy i przyjemniejszy w użyciu. To jest podstawowa zaleta operatora new - krótszy zapis. Wystarczy wiedzieć jakiego typu ma być obiekt, który chcemy powołać do życia, nie martwiąc się o rozmiar alokowanego bloku pamięci. Za pomocą operatora new można również tworzyć tablice wielowymiarowe: |
||
⚫ | Od razu widać, że drugi zapis jest |
||
<source lang="cpp"> |
<source lang="cpp"> |
||
int ** |
int **wektory = new int *[5]; |
||
for |
for (int i = 0; i < 5; ++i) |
||
wektory[i] = new int [10]; |
|||
</source> |
</source> |
||
W ten sposób stworzono tablicę dwuwymiarową którą statycznie zadeklarowalibyśmy jako: |
W ten sposób stworzono tablicę dwuwymiarową którą statycznie zadeklarowalibyśmy jako: |
||
<source lang="cpp"> |
<source lang="cpp"> |
||
int |
int wektory[5][10]; |
||
</source> |
</source> |
||
Jenak w przeciwieństwie do <code>int |
Jenak w przeciwieństwie do <code>int wektory[5][10]</code>, która jest tablicą dwuwymiarową, nasze <code>int **wektory</code> jest tablicą tablic i może być rozrzucone po całej pamięci. |
||
Ilość elementów poszczególnych wymiarów nie musi być jednakowa. Można np zadeklarować tablicę taką: |
Ilość elementów poszczególnych wymiarów nie musi być jednakowa. Można np zadeklarować tablicę taką: |
||
<source lang="cpp"> |
<source lang="cpp"> |
||
int ** |
int **wektory = new int *[2]; |
||
wektory[0] = new int [5]; |
|||
wektory[1] = new int; |
|||
</source> |
</source> |
||
Linia 40: | Linia 38: | ||
Deklaracja tablic o większej ilości wymiarów przebiega podobnie: |
Deklaracja tablic o większej ilości wymiarów przebiega podobnie: |
||
<source lang="cpp"> |
<source lang="cpp"> |
||
int *** |
int ***wektory; // deklarujemy tablicę 3-wymiarową |
||
wektory = new int **[5]; // pierwszy wymiar |
|||
wektory[0] = new int *[10]; // pierwszy element pierwszego wymiaru |
|||
wektory[1] = new int *[3]; // drugi element pierwszego wymiaru |
|||
.... |
.... |
||
wektory[0][0] = new int [3] // wymiar I = 0 -> wymiar II = 1 -> 3 elementy(tablica) |
|||
wektory[0][1] = new int [5] // wymiar I = 0 -> wymiar II = 3 -> 5 elementów(tablica) |
|||
wektory[1][0] = new int; // wymiar I = 1 -> wymiar II = 2 -> 1 element |
|||
... |
... |
||
</source> |
</source> |
||
Stosując ten |
Stosując ten sposób, ogólnie można deklarować tablice n-wymiarowe bez większego problemu. |
||
Usuwanie tablic wielowymiarowych przebiega podobnie jak jednowymiarowych z tą różnicą, że usuwanie zaczynamy od "najgłębszego" wymiaru: |
Usuwanie tablic wielowymiarowych przebiega podobnie jak jednowymiarowych, z tą różnicą, że usuwanie zaczynamy od "najgłębszego" wymiaru: |
||
<source lang="cpp"> |
<source lang="cpp"> |
||
⚫ | |||
int ***Wektory = new int **[2]; |
|||
delete [] wektory[0][1]; |
|||
delete [] wektory[1][0]; |
|||
Wektory[0][0] = new int; // pojedyncza zmienna dynamniczna! nie tablica |
|||
Wektory[0][1] = new int [5]; // zmienna tablicowa |
|||
Wektory[1][0] = new int [3]; |
|||
Wektory[1][1] = new int [2]; |
|||
... |
|||
// Kod programu |
|||
... |
|||
// III wymiar |
|||
⚫ | |||
delete [] Wektory[0][1]; |
|||
delete [] Wektory[1][0]; |
|||
delete [] Wektory[1][1]; |
|||
// II wymiar |
// II wymiar |
||
delete [] |
delete [] wektory[0]; |
||
delete [] |
delete [] wektory[1]; |
||
// I wymiar |
// I wymiar |
||
delete [] |
delete [] wektory; |
||
</source> |
</source> |
||
Wersja z 06:28, 1 lis 2011
W języku C++ do alokowania pamięci służy operator new a do zwalniania - delete. W C++ można również stosować funkcje malloc i free, jednak należy być ostrożnym. Najczęstszym błędem jest mieszanie operatorów new i delete z funkcjami malloc i free, np. zwalnianie pamięci zaalokowanej przez new przy pomocy free.
Rozważmy prosty przykład. Załóżmy, że chcemy stworzyć wektor 10 liczb typu całkowitego. Możemy to zrobić na dwa sposoby. W stylu znanym z języka C:
int *wektor = (int*) malloc (sizeof(int)*10);
free (wektor);
Albo w stylu C++:
int *wektor = new int[10];
delete [] wektor;
Od razu widać, że drugi zapis jest łatwiejszy i przyjemniejszy w użyciu. To jest podstawowa zaleta operatora new - krótszy zapis. Wystarczy wiedzieć jakiego typu ma być obiekt, który chcemy powołać do życia, nie martwiąc się o rozmiar alokowanego bloku pamięci. Za pomocą operatora new można również tworzyć tablice wielowymiarowe:
int **wektory = new int *[5];
for (int i = 0; i < 5; ++i)
wektory[i] = new int [10];
W ten sposób stworzono tablicę dwuwymiarową którą statycznie zadeklarowalibyśmy jako:
int wektory[5][10];
Jenak w przeciwieństwie do int wektory[5][10]
, która jest tablicą dwuwymiarową, nasze int **wektory
jest tablicą tablic i może być rozrzucone po całej pamięci.
Ilość elementów poszczególnych wymiarów nie musi być jednakowa. Można np zadeklarować tablicę taką:
int **wektory = new int *[2];
wektory[0] = new int [5];
wektory[1] = new int;
Przy takiej deklaracji pierwszy wiersz ma 5 elementów (tablica) a drugi to jeden element.
Deklaracja tablic o większej ilości wymiarów przebiega podobnie:
int ***wektory; // deklarujemy tablicę 3-wymiarową
wektory = new int **[5]; // pierwszy wymiar
wektory[0] = new int *[10]; // pierwszy element pierwszego wymiaru
wektory[1] = new int *[3]; // drugi element pierwszego wymiaru
....
wektory[0][0] = new int [3] // wymiar I = 0 -> wymiar II = 1 -> 3 elementy(tablica)
wektory[0][1] = new int [5] // wymiar I = 0 -> wymiar II = 3 -> 5 elementów(tablica)
wektory[1][0] = new int; // wymiar I = 1 -> wymiar II = 2 -> 1 element
...
Stosując ten sposób, ogólnie można deklarować tablice n-wymiarowe bez większego problemu.
Usuwanie tablic wielowymiarowych przebiega podobnie jak jednowymiarowych, z tą różnicą, że usuwanie zaczynamy od "najgłębszego" wymiaru:
delete wektory[0][0]; // kasujemy pojedynczą zmienną
delete [] wektory[0][1];
delete [] wektory[1][0];
// II wymiar
delete [] wektory[0];
delete [] wektory[1];
// I wymiar
delete [] wektory;
Zwrócić uwagę trzeba na dwie rzeczy:
delete []
używamy dla zmiennych tablicowych, adelete
dla pojedynczych zmiennych- Kolejność zwalniania wymiarów jest odwrotna niż ich tworzenia
Drugą zaletą jest fakt, że przy okazji alokacji pamięci możemy wywołać odpowiedni konstruktor inicjując wartości zmiennych obiektu, np.
Test *test = new Test(1,2);
zakładając, że obiekt Test posiada dwie zmienne typu całkowitego i zdefiniowany konstruktor Test(int,int)
.
Kolejną korzyścią jest możliwość przeciążania. Jednak to już jest temat na inny rozdział.