Destruktor-Muster
Teil des Abschnitts Objektorientierte Programmierung der C-Journey von Coddy. Lektion 13 von 61.
Jedes mit malloc erstellte Objekt muss schließlich freigegeben werden. So wie wir eine create_-Funktion geschrieben haben, um die Zuweisung zu verwalten, schreiben wir eine free_-Funktion, um die Bereinigung zu verwalten. Dies ist das Destruktor-Muster.
Die entscheidende Erkenntnis ist, dass die Freigabe in der umgekehrten Reihenfolge der Speicherzuweisung erfolgen muss. Wenn dein Konstruktor zuerst interne Member und anschließend die Struktur selbst reserviert hat, muss dein Destruktor zuerst die Member der Struktur und danach die Struktur freigeben:
typedef struct {
char *name;
int age;
} Person;
void free_person(Person *p) {
if (p == NULL) return; // Sicherheitsprüfung
free(p->name); // Zuerst internes Mitglied freigeben
free(p); // Dann die Struktur selbst freigeben
}
Die Prüfung auf NULL am Anfang verhindert Abstürze, falls jemand versehentlich einen ungültigen Zeiger übergibt. Nachdem wir die interne name-Zeichenkette freigegeben haben, geben wir die Struktur selbst frei. Wenn wir zuerst p freigeben würden, würden wir den Zugriff auf p->name verlieren und ein Speicherleck verursachen.
Die Verwendung des destructors 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 dir erstellte Objekt Speicher verlieren, bis deinem Programm der Speicher ausgeht.
Aufgabe
EinfachErstelle ein Movie-Modul, das den vollständigen Lebenszyklus eines Objekts veranschaulicht: sowohl seine Erstellung als auch seine Zerstörung. Du übst das Schreiben einer Destruktorfunktion, die den gesamten reservierten Speicher in der richtigen Reihenfolge ordnungsgemäß freigibt.
Du erstellst drei Dateien:
movie.h: Deklariere eineMovie-Struktur mit zwei Mitgliedern:char *title(eine dynamisch reservierte Zeichenkette) undint year. Deklariere sowohl einen Konstruktorcreate_movie, der einen Titel und ein Jahr entgegennimmt, als auch einen Destruktorfree_movie, der einen Movie-Zeiger entgegennimmt. Verwende Include-Schutz mit dem SymbolMOVIE_H.movie.c: Implementiere beide Funktionen. Dein Konstruktor sollte Speicher für die Struktur und ihre Titelzeichenkette reservieren (vergiss das Nullterminierungszeichen nicht). Dein Destruktor muss den Speicher in umgekehrter Reihenfolge der Reservierung freigeben: zuerst die internetitle-Zeichenkette, dann die Struktur selbst. Füge aus Sicherheitsgründen am Anfang deines Destruktors eine NULL-Prüfung ein.main.c: Erstelle einen Film, gib seine Informationen aus und räume anschließend den Speicher ordnungsgemäß auf.
Du erhältst zwei Eingaben: den Filmtitel (eine Zeichenkette) und das Veröffentlichungsjahr (eine Ganzzahl).
Verwende in deiner Hauptdatei create_movie, um einen neuen Film zu erstellen, gib seine Informationen aus und rufe anschließend free_movie auf, um den gesamten Speicher freizugeben. Gib nach der Freigabe eine Bestätigungsnachricht aus.
Gib die Ausgabe in diesem Format aus:
Movie: {title} ({year})
Memory freedBeispielsweise würde die Ausgabe bei den Eingaben Inception und 2010 folgendermaßen aussehen:
Movie: Inception (2010)
Memory freedDenke daran: Der Schlüssel zu einem ordnungsgemäßen Destruktor besteht darin, den Speicher in umgekehrter Reihenfolge freizugeben. Was dein Konstruktor zuerst reserviert, wird zuletzt freigegeben, und was er zuletzt reserviert, wird zuerst freigegeben.
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 im Format aus:
// Film: {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 Objektorientierte Programmierung
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-ImplementierungRechteck-ImplementierungPolymorphe VerwendungShape-ContainerÜbe selbstständig: Online-C-Compiler