C++/Zarządzanie pamięcią: Różnice pomiędzy wersjami

Z Wikibooks, biblioteki wolnych podręczników.
< C++
Usunięta treść Dodana treść
m poprawa linków
Piotr (dyskusja | edycje)
mNie podano opisu zmian
Linia 2: Linia 2:


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:
<pre class="lang-cpp">
int *Wektor = (int*)malloc(sizeof(int)*10);
int *Wektor = (int*)malloc(sizeof(int)*10);
free(Wektor);
free(Wektor);
albo w stylu C++:
albo w stylu C++:
int *Wektor = new int[10];
int *Wektor = new int[10];
delete Wektor;
delete Wektor;
</pre>




Od razu widać, że drugi zapis jest zdecydowanie ł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 zdecydowanie ł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:
<pre class="lang-cpp">
int **Wektory = new int *[5];
for( int i=0; i<5; i++ )
int **Wektory = new int *[5];
for( int i=0; i<5; i++ )
Wektory[i] = new int [10];
Wektory[i] = new int [10];
</pre>



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:
<pre class="lang-cpp">
int Wektory[5][10];
int Wektory[5][10];
</pre>




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ą:
<pre class="lang-cpp">
int **Wektory = new int *[2];
Wektory[0] = new int [5];
int **Wektory = new int *[2];
Wektory[1] = new int;
Wektory[0] = new int [5];
Wektory[1] = new int;
</pre>




Przy takiej deklaracji pierwszy wiersz ma 5 elementów (tablica) a drugi to jeden element.
Przy takiej deklaracji pierwszy wiersz ma 5 elementów (tablica) a drugi to jeden element.
Deklaracja tablic więcej wymarowych przebiega podobnie:
Deklaracja tablic więcej wymarowych przebiega podobnie:
<pre class="lang-cpp">
int ***Wektory = NULL; // deklarujemy tablicę 3-wymiarową
Wektory = = new int **[5]; // pierwszy wymiar
int ***Wektory = NULL; // deklarujemy tablicę 3-wymiarową
Wektory[0] = new int *[10]; // pierwszy element pierwszego wymiaru
Wektory = = new int **[5]; // pierwszy wymiar
Wektory[1] = new int *[3]; // drugi element pierwszego wymiaru
Wektory[0] = new int *[10]; // pierwszy element pierwszego wymiaru
Wektory[1] = new int *[3]; // drugi element pierwszego wymiaru
....
....
Wektory[0][1] = new int [3] // wymiar I = 0 -> wymiar II = 1 -> 3 elementy(tablica)
Wektory[0][3] = new int [5] // wymiar I = 0 -> wymiar II = 3 -> 5 elementów(tablica)
Wektory[0][1] = new int [3] // wymiar I = 0 -> wymiar II = 1 -> 3 elementy(tablica)
Wektory[1][2] = new int; // wymiar I = 1 -> wymiar II = 2 -> 1 element
Wektory[0][3] = new int [5] // wymiar I = 0 -> wymiar II = 3 -> 5 elementów(tablica)
Wektory[1][2] = new int; // wymiar I = 1 -> wymiar II = 2 -> 1 element
...
...
</pre>




Stosując ten algorytm ogólnie można deklarować tablice n-wymiarowe bez większego problemu.
Stosując ten algorytm 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:
<pre class="lang-cpp">
int ***Wektory = new int **[2];
Wektory[0] = new int *[2];
int ***Wektory = new int **[2];
Wektory[1] = new int *[2];
Wektory[0] = new int *[2];
Wektory[0][0] = new int; // pojedyńcza zmienna dynamniczna! nie tablica
Wektory[1] = new int *[2];
Wektory[0][0] = new int; // pojedyńcza zmienna dynamniczna! nie tablica
Wektory[0][1] = new int [5]; // zmienna tablicowa
Wektory[0][1] = new int [5]; // zmienna tablicowa
Wektory[1][0] = new int [3];
Wektory[1][0] = new int [3];
Wektory[1][1] = new int [2];
Wektory[1][1] = new int [2];
...
...
// Kod programu
// Kod programu
...
...
// III wymiar
// III wymiar
delete Wektory[0][0]; // kasujemy pojedyńczą zmienną
delete Wektory[0][0]; // kasujemy pojedyńczą zmienną
delete [] Wektory[0][1];
delete [] Wektory[0][1];
delete [] Wektory[1][0];
delete [] Wektory[1][0];
delete [] Wektory[1][1];
delete [] Wektory[1][1];
// II wymiar
// II wymiar
delete [] Wektory[0];
delete [] Wektory[0];
delete [] Wektory[1];
delete [] Wektory[1];
// I wymiar
// I wymiar
delete [] Wektory;
delete [] Wektory;
</pre>



Zwrócić uwagę trzeba na dwie rzeczy:
Zwrócić uwagę trzeba na dwie rzeczy:
Linia 70: Linia 80:


Drugą zaletą jest fakt, że przy okazji alokacji pamięci możemy wywołać odpowiedni konstruktor inicjalizując wartości zmiennych obiektu, np.
Drugą zaletą jest fakt, że przy okazji alokacji pamięci możemy wywołać odpowiedni konstruktor inicjalizując wartości zmiennych obiektu, np.
<pre class="lang-cpp">
Test *Test = new Test(1,2);
Test *Test = new Test(1,2);
</pre>
zakładając, że obiekt Test posiada dwie zmienne typu całkowitego i zdefiniowany konstruktor Test(int,int).
zakładając, że obiekt Test posiada dwie zmienne typu całkowitego i zdefiniowany konstruktor Test(int,int).



Wersja z 11:31, 2 lis 2006

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 zdecydowanie ł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];


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 więcej wymarowych przebiega podobnie:

int ***Wektory = NULL;      // 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][1] = new int [3] // wymiar I = 0 -> wymiar II = 1 -> 3 elementy(tablica)
Wektory[0][3] = new int [5] // wymiar I = 0 -> wymiar II = 3 -> 5 elementów(tablica)
Wektory[1][2] = new int;    // wymiar I = 1 -> wymiar II = 2 -> 1 element
...


Stosując ten algorytm 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:

int ***Wektory = new int **[2];
Wektory[0] = new int *[2];
Wektory[1] = new int *[2];
Wektory[0][0] = new int;     // pojedyńcza 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][0];        // kasujemy pojedyńczą zmienną
delete [] Wektory[0][1];
delete [] Wektory[1][0];
delete [] Wektory[1][1];
// II wymiar
delete [] Wektory[0];
delete [] Wektory[1];
// I wymiar
delete [] Wektory;

Zwrócić uwagę trzeba na dwie rzeczy:

  1. delete [] używamy dla zmiennych tablicowych a delete dla pojedyńczych zmiennych
  2. 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 inicjalizują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ł.

Szablon:ProstaNawigacja