To znaczy, rozumiem, że pozwalają zwolnić pamięć, ale gdzieś wyczytałem, że po usunięciu obiektu klasy jest ona zwalniana automatycznie
Tylko jeśli obiekt jest na stosie. Jeśli masz np wskaźnik do pamięci na stercie, program sam z nim nic nie robi:
{
int *x = new int;
} // wyciek pamieci
Na przykład jeśli masz std::string, który w uproszczeniu wygląda tak:
class string {
size_t length;
char *data;
// metody
};
Zadaniem destruktora std::string jest zapewnienie, że pamięć `data` zostanie automatycznie zwolniona. Dzięki temu nie musisz pisać:
void f(){
std::string s;
// cos robisz ze stringiem
delete s.data;
}
Tylko wystarczy:
void f(){
std::string s;
// cos robisz ze stringiem
} // destruktor zwalnia pamięć
Analogicznie dla np otwartych plików. Bez destruktorów musiałbyś zawsze się pilnować i pisać:
void f(){
ifstream f("dane.txt");
if (warunek) {
f.close(); // trzeba zamknac plik przed wyjsciem!
return;
}
try {
cos_co_moze_rzucic_wyjatkiem();
} catch (std::exception &e) {
f.close(); // trzeba zamknac plik!
return;
}
costam();
f.close(); // trzeba zamknac plik przed wyjsciem!
}
Ale destruktor zamknie plik za Ciebie. Do tego, destruktory mają potężną właściwość, że dla obiektów automatycznych praktycznie zawsze się wywołują - nie musisz się przejmować if'ami, wczesnymi returnami, wyjątkami.
void f(){
ifstream f("dane.txt");
if (warunek)
return;
cos_co_moze_rzucic_wyjatkiem();
costam();
} // masz gwarancje ze `f.close()` sie wywola
czy może jest to tylko dobra praktyka, która wywodzi się z dawniejszych czasów c++?
Destruktory (i RAII) to kluczowy, jeśli nie najważniejszy, ficzer C++a. Ich ważność tylko rośnie z czasem.