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.
Wyzwanie
ŁatwyZbudujmy 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ęMoviez dwoma polami:char *title(dynamicznie przydzielany ciąg znaków) iint year. Zadeklaruj zarówno konstruktorcreate_movie, który przyjmuje tytuł i rok, jak i destruktorfree_movie, który przyjmuje wskaźnik do Movie. Użyj strażników dołączania z symbolemMOVIE_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ówtitle, 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 freedNa przykład dla danych wejściowych Inception i 2010 wynik wyglądałby tak:
Movie: Inception (2010)
Memory freedPamię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;
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania modularnego
Pliki nagłówkoweZabezpieczenia przed wielokrotnym dołączeniemPliki źródłoweFunkcje statycznePodsumowanie: kalkulator modularny4Enkapsulacja
Koncepcja niejawnych wskaźnikówDefiniowanie niejawnych strukturGettery i setteryWalidacja w setterachPowtórka: tajemnicze pudełko2Obiekty i metody
Struktury jako obiektyWskaźnik „self”Poprawność constWskaźnik czy wartośćMetody pomocniczePodsumowanie: menedżer punktów5Projekt: Proste konto bankowe
Konfiguracja projektuImplementacja konta8Polimorfizm
Wskaźniki do funkcji w strukturachSymulowanie metodKoncepcja interfejsuImplementowanie interfejsówIteracja polimorficznaPodsumowanie: Greeter11Wzorce projektowe w C
Wzorzec SingletonWzorzec fabrykiWzorzec iteratoraPodsumowanie: fabryka loggera3Cykl życia obiektu
Wzorzec konstruktoraWzorzec destruktoraInicjalizacja na stosieKopia głębokaPodsumowanie: klasa opakowująca ciąg znaków6Dziedziczenie przez kompozycję
Osadzanie strukturZasada pierwszego elementuDostęp do elementów klasy nadrzędnejKonwersja w górę hierarchiiPodsumowanie: hierarchia kształtów9Projekt: Rysownik kształtów
Przegląd projektuImplementacja kołaImplementacja prostokątaZastosowanie polimorfizmuKontener kształtówPoćwicz samodzielnie: Kompilator C online