Destruktor-Muster
Teil des Abschnitts Object Oriented Programming der C-Journey von Coddy — Lektion 13 von 61.
Jedes Objekt, das mit malloc erstellt wurde, muss schließlich freigegeben werden. Genauso wie wir eine create_-Funktion geschrieben haben, um die Allokation zu handhaben, schreiben wir eine free_-Funktion, um das Aufräumen zu handhaben. Dies ist das Destruktor-Muster.
Die entscheidende Erkenntnis ist, dass das Freigeben in umgekehrter Reihenfolge der Allokation erfolgen muss. Wenn Ihr Konstruktor zuerst interne Member und dann das Struct selbst allokiert hat, muss Ihr Destruktor zuerst die Member des Structs und dann das Struct selbst freigeben:
typedef struct {
char *name;
int age;
} Person;
void free_person(Person *p) {
if (p == NULL) return; // Sicherheitsprüfung
free(p->name); // Zuerst internes Element freigeben
free(p); // Dann das Struct selbst freigeben
}
Die NULL-Prüfung am Anfang verhindert Abstürze, falls versehentlich ein ungültiger Pointer übergeben wird. Nach dem Freigeben des internen name-Strings geben wir das Struct selbst frei. Wenn wir zuerst p freigeben würden, verlören wir den Zugriff auf p->name und würden ein Speicherleck verursachen.
Die Verwendung des Destruktors ist unkompliziert:
Person *alice = create_person("Alice", 30);
// ... alice verwenden ...
free_person(alice); // Aufräumen, wenn fertig
Dieses Muster stellt sicher, dass der gesamte Speicher ordnungsgemäß freigegeben wird. Ohne dieses Muster würde jedes von Ihnen erstellte Objekt Speicherlecks verursachen, bis Ihrem Programm der Speicher ausgeht.
Aufgabe
EinfachLassen Sie uns ein Movie-Modul erstellen, das den vollständigen Objektlebenszyklus demonstriert – sowohl die Erstellung als auch die Zerstörung. Sie werden üben, eine Destruktor-Funktion zu schreiben, die den gesamten zugewiesenen Speicher ordnungsgemäß in der richtigen Reihenfolge bereinigt.
Sie werden drei Dateien erstellen:
movie.h: Deklarieren Sie einMovie-Struct mit zwei Elementen:char *title(ein dynamisch zugewiesener String) undint year. Deklarieren Sie sowohl einen Konstruktorcreate_movie, der einen Titel und ein Jahr entgegennimmt, als auch einen Destruktorfree_movie, der einen Movie-Pointer entgegennimmt. Verwenden Sie Include-Guards mit dem SymbolMOVIE_H.movie.c: Implementieren Sie beide Funktionen. Ihr Konstruktor sollte Speicher für das Struct und seinen Titel-String reservieren (vergessen Sie nicht den Null-Terminator). Ihr Destruktor muss den Speicher in umgekehrter Reihenfolge der Zuweisung freigeben – zuerst den internentitle-String, dann das Struct selbst. Fügen Sie zur Sicherheit eine NULL-Prüfung am Anfang Ihres Destruktors ein.main.c: Erstellen Sie einen Film, zeigen Sie seine Informationen an und bereinigen Sie dann ordnungsgemäß den Speicher.
Sie erhalten zwei Eingaben: den movie title (einen String) und das release year (eine Ganzzahl).
Verwenden Sie in Ihrer Hauptdatei create_movie, um einen neuen Film zu erstellen, geben Sie seine Informationen aus und rufen Sie dann free_movie auf, um den gesamten Speicher freizugeben. Geben Sie nach dem Freigeben eine Bestätigungsmeldung aus.
Geben Sie die Ausgabe in diesem Format aus:
Movie: {title} ({year})
Memory freedZum Beispiel wäre bei den Eingaben Inception und 2010 die Ausgabe:
Movie: Inception (2010)
Memory freedDenken Sie daran: Der Schlüssel zu einem ordnungsgemäßen Destruktor ist das Freigeben in umgekehrter Reihenfolge. Was Ihr Konstruktor zuerst reserviert, wird zuletzt freigegeben, und was er zuletzt reserviert, wird zuerst freigegeben.
Spickzettel
Jedes mit malloc erstellte Objekt muss mit einer Destruktor-Funktion freigegeben werden. Destruktoren folgen dem Muster, Speicher in umgekehrter Reihenfolge der Allokation freizugeben.
Grundlegende Destruktor-Struktur:
typedef struct {
char *name;
int age;
} Person;
void free_person(Person *p) {
if (p == NULL) return; // Sicherheitsprüfung
free(p->name); // Zuerst interne Member freigeben
free(p); // Dann das Struct selbst freigeben
}
Schlüsselprinzipien:
- Fügen Sie am Anfang immer eine
NULL-Prüfung ein, um Abstürze zu verhindern - Geben Sie interne Member frei, bevor Sie das Struct selbst freigeben
- Wenn Sie zuerst das Struct freigeben, verlieren Sie den Zugriff auf seine Member und verursachen Speicherlecks
Verwendungsbeispiel:
Person *alice = create_person("Alice", 30);
// ... alice verwenden ...
free_person(alice); // Aufräumen, wenn fertig
Probier es selbst
#include <stdio.h>
#include <stdlib.h>
#include "movie.h"
int main() {
char title[100];
int year;
// Eingabe lesen
scanf("%[^\n]", title);
scanf("%d", &year);
// TODO: Erstelle einen Film mit create_movie
// TODO: Gib die Filminformationen in folgendem Format aus:
// Movie: {title} ({year})
// TODO: Gib den Film mit free_movie frei
// TODO: Gib "Memory freed" aus
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
1Grundlagen der modularen Programmierung
Header-DateienInclude GuardsQuelldateienStatische FunktionenWiederholung: Modularer Taschenrechner4Kapselung
Konzept der Opaque PointersOpaque Structs definierenGetter und SetterValidierung in SetternRückblick: Die geheime Box2Objekte und Methoden
Structs als ObjekteDer 'Self'-PointerConst-CorrectnessPointer vs. WertHilfsmethodenZusammenfassung: Point Manager5Projekt: Einfaches Bankkonto
Projekt-SetupImplementierung des Kontos3Objekt-Lebenszyklus
Konstruktor-MusterDestruktor-MusterStack-InitialisierungTiefe KopieRückblick: String-Wrapper6Vererbung durch Komposition
Struct-EinbettungDie First-Member-RegelZugriff auf Parent-MemberUpcastingRückblick: Formenhierarchie9Projekt: Formen-Zeichner
ProjektübersichtKreis-Implementierung