Menu
Coddy logo textTech

Wzorzec destruktora

Część sekcji Programowanie obiektowe ścieżki C w Coddy. Lekcja 13 z 61.

Każdy obiekt utworzony za pomocą malloc musi w końcu zostać zwolniony. Tak jak napisaliśmy funkcję create_ do obsługi przydzielania pamięci, tak piszemy funkcję free_ do obsługi sprzątania. To wzorzec destruktora.

Kluczowa kwestia jest taka, że zwalnianie pamięci musi odbywać się w odwrotnej kolejności niż jej przydzielanie. Jeśli konstruktor najpierw przydzielił pamięć dla wewnętrznych składowych, a następnie dla samej struktury, destruktor musi najpierw zwolnić pamięć składowych struktury, a potem samej struktury:

typedef struct {
    char *name;
    int age;
} Person;

void free_person(Person *p) {
    if (p == NULL) return;  // Sprawdzenie bezpieczeństwa
    free(p->name);          // Najpierw zwolnij pamięć zajmowaną przez wewnętrzne pole
    free(p);                // Następnie zwolnij pamięć zajmowaną przez samą strukturę
}

Sprawdzenie NULL na początku zapobiega awariom, jeśli ktoś przypadkowo przekaże nieprawidłowy wskaźnik. Po zwolnieniu wewnętrznego ciągu znaków name zwalniamy samą strukturę. Gdybyśmy najpierw zwolnili p, utracilibyśmy dostęp do p->name i spowodowali wyciek pamięci.

Użycie destruktora jest proste:

Person *alice = create_person("Alice", 30);
// ... użyj alice ...
free_person(alice);  // Zwolnij zasoby po zakończeniu

Ten wzorzec zapewnia prawidłowe zwolnienie całej pamięci. Bez niego każdy utworzony obiekt powodowałby wyciek pamięci, aż do jej wyczerpania przez program.

challenge icon

Wyzwanie

Łatwy

Zbudujmy moduł Movie, który przedstawia pełny cykl życia obiektu: zarówno jego tworzenie, jak i niszczenie. Poćwiczysz pisanie funkcji destruktora, która prawidłowo zwalnia całą przydzieloną pamięć we właściwej kolejności.

Utworzysz trzy pliki:

  • movie.h: Zadeklaruj strukturę Movie z dwoma polami: char *title (dynamicznie przydzielany ciąg znaków) i int year. Zadeklaruj zarówno konstruktor create_movie, który przyjmuje tytuł i rok, jak i destruktor free_movie, który przyjmuje wskaźnik do Movie. Użyj strażników dołączania z symbolem MOVIE_H.
  • movie.c: Zaimplementuj obie funkcje. Konstruktor powinien przydzielić pamięć dla struktury i jej ciągu znaków title (nie zapomnij o znaku null). Destruktor musi zwolnić pamięć w odwrotnej kolejności przydzielania: najpierw wewnętrzny ciąg znaków title, a następnie samą strukturę. Dla bezpieczeństwa umieść na początku destruktora sprawdzenie NULL.
  • main.c: Utwórz film, wyświetl jego informacje, a następnie prawidłowo zwolnij pamięć.

Otrzymasz dwa dane wejściowe: tytuł filmu (ciąg znaków) i rok premiery (liczba całkowita).

W pliku głównym użyj create_movie, aby utworzyć nowy film, wyświetl jego informacje, a następnie wywołaj free_movie, aby zwolnić całą pamięć. Po jej zwolnieniu wyświetl komunikat potwierdzający.

Wyświetl wynik w tym formacie:

Movie: {title} ({year})
Memory freed

Na przykład dla danych wejściowych Inception i 2010 wynik wyglądałby tak:

Movie: Inception (2010)
Memory freed

Pamiętaj: kluczem do prawidłowego destruktora jest zwalnianie pamięci w odwrotnej kolejności. To, co konstruktor przydziela jako pierwsze, jest zwalniane jako ostatnie, a to, co przydziela jako ostatnie, jest zwalniane jako pierwsze.

Spróbuj swoich sił

#include <stdio.h>
#include <stdlib.h>
#include "movie.h"

int main() {
    char title[100];
    int year;
    
    // Odczytaj dane wejściowe
    scanf("%[^\n]", title);
    scanf("%d", &year);
    
    // TODO: Utwórz film za pomocą create_movie
    
    // TODO: Wypisz informacje o filmie w formacie:
    // Film: {title} ({year})
    
    // TODO: Zwolnij pamięć zajmowaną przez film za pomocą free_movie
    
    // TODO: Wypisz "Memory freed"
    
    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