Zacznijmy od tego że w języku C++ mamy cztery rodzaje pamięci:
- Pamięć automatyczn
- Pamięć dynamiczn
- Pamięć statyczn
- Pamięć wątku
Pamięci wątku oraz statycznej nie będę omawiał. Zajmiemy się tylko pamięcią automatyczna i dynamiczną. Pierwsza z nich czyli pamięć automatyczna to nic innego jak zmienne „zwykłe” czyli np int x, zmienna x należy do pamięci automatycznej, tak samo Moja_klasa k to również pamięć automatyczna. Pamięć ta charakteryzuje się tym że zmienne należące do tego rodzaju pamięci są automatycznie usuwane po wyjściu z bloku kodu lub funkcji.
Pamięć dynamiczna to wszystko co tworzymy za pomocą operatora new, zmienne, obiekty będą żyły, zajmowały zasoby dopóki nie zostanie pamięć na nasze życzenie zwolniona za pomocą operatora delete.
Oczywiści zasoby zarezerowane za pomocą new zostaną zwolnione przez system po zakończeniu programu.
Weźmy taki program:
#include <iostream>
using namespace std;
class Moja_klasa
{
public:
Moja_klasa()
{
cout<<"Konstruktor"<<endl;
}
~Moja_klasa()
{
cout<<"Destruktor"<<endl;
}
};
int main()
{
Moja_klasa moja;
return 0;
}
Uruchamiając ten program naszym oczom ukaże się napis Konstruktor, a zaraz pod nim Destruktor. W funkcji main tworzymy obiekt moja, dlatego wywołuje się konstruktor zaś zaraz po tym funkcja main się kończy więc nasz obiekt jest niszczony.
Proponuję teraz zmodyfikować nasz program na taki:
#include <iostream>
using namespace std;
class Moja_klasa
{
public:
Moja_klasa()
{
cout<<"Konstruktor"<<endl;
}
~Moja_klasa()
{
cout<<"Destruktor"<<endl;
}
};
int main()
{
Moja_klasa *moja=new Moja_klasa();
return 0;
}
W tym przypadku tworzymy obiekt dynamicznie za pomocą operatora new. Jak pewnie zauważyłeś na standardowe wyjście wypisuje się tylko napis Konstruktor oznaczający ze tylko konstruktor został wykonany. Jest to jak najbardziej normalne, operator new powoduje wysłanie konstruktora. Jeśli chcieli byśmy zwolnić zasoby, zarazem wywołać destruktor powinniśmy użyć operatora delete. Zobaczymy więc na kolejny przykład:
#include <iostream>
using namespace std;
class Moja_klasa
{
public:
Moja_klasa()
{
cout<<"Konstruktor"<<endl;
}
~Moja_klasa()
{
cout<<"Destruktor"<<endl;
}
};
int main()
{
Moja_klasa *moja=new Moja_klasa();
delete moja;
return 0;
}
Teraz naszym oczom powinien ukazać się zarówno napis Konstruktor jak i Destruktor. Zasadniczo konstruktor jest to metoda która „konfiguruje”, przygotowuje nasz obiekt do działania, istnienia. Zaś destruktor to metoda która sprząta po obiekcie, to właśnie w nim powinna znaleść się realokacja pamięci zablokowanej przez konstruktor czy zakończenia połączenia z bazą danych.
Operator new jak i delete stanowią parę, pierwszy z nich wywołuj konstruktor zaś drugi destruktor. Ponadto odpowiednio rezerwują pamięć, oraz ja dealokują. Nigdy nie wolno mieszać operatora new i delete z funkcjami pochodzącymi z języka C takimi jak malloc, calloc, realloc czy free. Jeśli tworzymy obiekt za pomocą new nie możemy go usunąć funkcja free, to samo jeśli tworzymy obiekt funkcją malloc nie możemy go zwolnić operatorem delete. Nie zwolnienie zasobów stworzonych w pamięci dynamicznej może skutkować wyciekiem pamięci. Pamiętaj również że jednemu operatorowi new powinien odpowiadać jeden operator delete. Nie można kilkakrotnie usuwać już zwolnione pamięci jak i tworzyć kilkukornie nowego obszaru pamięci bez uprzednio zwolnienia starego.