Menu
Coddy logo textTech

Destruktor — szczegółowe omówienie

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 24 z 104.

Destruktor to specjalna funkcja składowa, która uruchamia się automatycznie, gdy obiekt zostaje zniszczony. Jej głównym zadaniem jest zwalnianie zasobów, które obiekt pozyskał w trakcie swojego istnienia, takich jak dynamicznie alokowana pamięć, uchwyty do plików lub połączenia sieciowe.

Destruktor ma taką samą nazwę jak klasa, poprzedzoną tyldą ~. Nie przyjmuje żadnych parametrów i nie ma typu zwracanego:

class FileHandler {
    std::string filename;
    int* buffer;
public:
    FileHandler(std::string name, size_t size) 
        : filename(name), buffer(new int[size]) {
        std::cout << "Opening " << filename << "\n";
    }
    ~FileHandler() {
        delete[] buffer;
        std::cout << "Closing " << filename << "\n";
    }
};

Destruktory są wywoływane automatycznie w następujących sytuacjach:

  • Obiekty na stosie wychodzą poza zakres
  • Na obiekcie zaalokowanym na stercie wywoływane jest delete
  • Kończy się czas życia obiektu tymczasowego
void example() {
    FileHandler f1("data.txt", 100);    // Wywołano konstruktor
    FileHandler* f2 = new FileHandler("log.txt", 50);
    delete f2;                           // Wywołano destruktor dla f2
}   // Wywołano destruktor dla f1 (wychodzi poza zakres)

W przeciwieństwie do konstruktorów klasa może mieć tylko jeden destruktor. Nie można go przeciążać.

Jeśli go nie zdefiniujesz, kompilator wygeneruje domyślny destruktor, który nie robi niczego szczególnego — po prostu niszczy każdy element członkowski. W przypadku klas zarządzających zasobami musisz napisać własny, aby zapobiec wyciekom pamięci.

challenge icon

Wyzwanie

Łatwy

Zbudujmy menedżer sesji, który śledzi aktywne sesje użytkowników i pokazuje, jak destruktory automatycznie zwalniają zasoby, gdy obiekty są niszczone — zarówno gdy wychodzą poza zakres, jak i gdy są jawnie usuwane.

Utworzysz dwa pliki, aby uporządkować swój kod:

  • Session.h: Zdefiniuj klasę Session, która reprezentuje aktywną sesję użytkownika z danymi zaalokowanymi dynamicznie. Twoja klasa powinna mieć:
    • Prywatne składowe: username (string), sessionId (int) oraz wskaźnik do tablicy liczb całkowitych o nazwie activityLog, która śledzi działania użytkownika, a także logSize określający rozmiar tablicy
    • Konstruktor przyjmujący nazwę użytkownika, identyfikator sesji i rozmiar dziennika. Powinien zaalokować tablicę dziennika aktywności na stercie, zainicjować wszystkie elementy wartością 0 i wypisać "Session <sessionId> started for <username>"
    • Destruktor, który zwalnia zaalokowaną pamięć i wypisuje "Session <sessionId> ended for <username>"
    • Metodę logActivity(int activityCode), która zapisuje kod aktywności w następnym dostępnym miejscu (bieżąca pozycja powinna być śledzona wewnętrznie); jeśli dziennik jest już pełny, wywołanie jest ignorowane, więc liczba nigdy nie przekracza jego rozmiaru
    • Metodę getActivityCount(), która zwraca liczbę zapisanych aktywności
    • Metodę getUsername(), która zwraca nazwę użytkownika
  • main.cpp: Pokaż działanie destruktora w różnych sytuacjach. Odczytaj z wejścia nazwę użytkownika i rozmiar dziennika (każdą wartość w osobnym wierszu), a następnie:
    • Utwórz blok zakresu za pomocą nawiasów klamrowych { }, a wewnątrz niego utwórz obiekt Session alokowany na stosie, używając wczytanej nazwy użytkownika, identyfikatora sesji 101 i wczytanego rozmiaru dziennika. Zapisz dwie aktywności o kodach 1 i 2, a następnie wypisz "Stack session activities: <count>". Po zakończeniu bloku destruktor powinien uruchomić się automatycznie.
    • Po bloku wypisz "Stack session destroyed"
    • Utwórz obiekt Session alokowany na stercie za pomocą new, używając nazwy użytkownika "Guest", identyfikatora sesji 202 i rozmiaru dziennika 3. Zapisz jedną aktywność o kodzie 5, wypisz "Heap session activities: <count>", a następnie jawnie go delete.
    • Po usunięciu wypisz "Heap session destroyed"

To wyzwanie pokazuje dwa główne sposoby wywoływania destruktorów: automatycznie, gdy obiekty alokowane na stosie wychodzą poza zakres, oraz ręcznie, gdy usuwasz obiekty alokowane na stercie. Obie ścieżki powinny poprawnie zwalniać dynamicznie zaalokowany dziennik aktywności, aby zapobiec wyciekom pamięci.

Dołącz plik nagłówkowy w pliku main.cpp za pomocą #include "Session.h".

Spróbuj swoich sił

#include <iostream>
#include <string>
#include "Session.h"

using namespace std;

int main() {
    // Wczytaj dane wejściowe
    string username;
    int logSize;
    getline(cin, username);
    cin >> logSize;
    
    // TODO: Utwórz blok zakresu za pomocą nawiasów klamrowych { }
    // Wewnątrz bloku:
    //   - Utwórz Session na stosie, używając wczytanej nazwy użytkownika, identyfikatora sesji 101 i wczytanego rozmiaru dziennika
    //   - Zarejestruj dwie aktywności o kodach 1 i 2
    //   - Wypisz "Stack session activities: <count>"
    // Po zakończeniu bloku destruktor uruchomi się automatycznie
    
    // TODO: Po zakończeniu bloku wypisz "Stack session destroyed"
    
    // TODO: Utwórz Session na stercie za pomocą new
    //   - Nazwa użytkownika: "Guest", identyfikator sesji: 202, rozmiar dziennika: 3
    //   - Zarejestruj jedną aktywność o kodzie 5
    //   - Wypisz "Heap session activities: <count>"
    //   - Usuń sesję
    
    // TODO: Po usunięciu wypisz "Heap session destroyed"
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online