Destruktor im Detail
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 24 von 104.
Ein Destruktor ist eine spezielle Memberfunktion, die automatisch ausgeführt wird, wenn ein Objekt zerstört wird. Seine Hauptaufgabe besteht darin, Ressourcen freizugeben, die das Objekt während seiner Lebensdauer erworben hat, etwa dynamisch zugewiesenen Speicher, Dateihandles oder Netzwerkverbindungen.
Der Destruktor hat denselben Namen wie die Klasse, dem eine Tilde vorangestellt ist: ~. Er nimmt keine Parameter entgegen und hat keinen Rückgabetyp:
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";
}
};Destruktoren werden in diesen Situationen automatisch aufgerufen:
- Stack-Objekte verlassen den Gültigkeitsbereich
deletewird für ein heap-allokiertes Objekt aufgerufen- Die Lebensdauer eines temporären Objekts endet
void example() {
FileHandler f1("data.txt", 100); // Konstruktor aufgerufen
FileHandler* f2 = new FileHandler("log.txt", 50);
delete f2; // Destruktor für f2 aufgerufen
} // Destruktor für f1 aufgerufen (verlässt den Gültigkeitsbereich)Im Gegensatz zu Konstruktoren kann eine Klasse nur einen Destruktor haben. Du kannst ihn nicht überladen.
Wenn du keinen definierst, erzeugt der Compiler einen Standarddestruktor, der nichts Besonderes tut – er zerstört einfach jedes Mitglied. Bei Klassen, die Ressourcen verwalten, musst du deinen eigenen schreiben, um Speicherlecks zu verhindern.
Aufgabe
EinfachErstelle einen Sitzungsmanager, der aktive Benutzersitzungen verfolgt und zeigt, wie Destruktoren Ressourcen automatisch bereinigen, wenn Objekte zerstört werden – unabhängig davon, ob sie den Gültigkeitsbereich verlassen oder explizit gelöscht werden.
Du erstellst zwei Dateien, um deinen Code zu organisieren:
Session.h: Definiere eineSession-Klasse, die eine aktive Benutzersitzung mit dynamisch zugewiesenen Daten darstellt. Deine Klasse sollte Folgendes enthalten:- Private Member: einen
username(String), einesessionId(Ganzzahl) und einen Zeiger auf ein Ganzzahl-Array namensactivityLog, das Benutzeraktionen verfolgt, sowie einlogSizefür die Arraygröße - Einen Konstruktor, der einen Benutzernamen, eine Sitzungs-ID und eine Protokollgröße entgegennimmt. Er sollte das Aktivitätsprotokoll-Array auf dem Heap zuweisen, alle Elemente mit 0 initialisieren und
"Session <sessionId> started for <username>"ausgeben - Einen Destruktor, der den zugewiesenen Speicher freigibt und
"Session <sessionId> ended for <username>"ausgibt - Eine
logActivity(int activityCode)-Methode, die den Aktivitätscode im nächsten verfügbaren Eintrag speichert (die aktuelle Position soll intern verfolgt werden) - Eine
getActivityCount()-Methode, die zurückgibt, wie viele Aktivitäten protokolliert wurden - Eine
getUsername()-Methode, die den Benutzernamen zurückgibt
- Private Member: einen
main.cpp: Veranschauliche das Verhalten von Destruktoren in verschiedenen Szenarien. Lies einen Benutzernamen und eine Protokollgröße aus der Eingabe ein (jeweils in einer eigenen Zeile), und führe anschließend Folgendes aus:- Erstelle mit geschweiften Klammern
{ }einen Gültigkeitsbereich und erstelle darin eine auf dem Stack zugewieseneSessionmit dem eingegebenen Benutzernamen, der Sitzungs-ID101und der eingegebenen Protokollgröße. Protokolliere zwei Aktivitäten mit den Codes1und2und gib anschließend"Stack session activities: <count>"aus. Wenn der Block endet, sollte der Destruktor automatisch ausgeführt werden. - Gib nach dem Block
"Stack session destroyed"aus - Erstelle mithilfe von
Sessioneine auf dem Heap zugewiesenenewmit dem Benutzernamen"Guest", der Sitzungs-ID202und der Protokollgröße3. Protokolliere eine Aktivität mit dem Code5, gib"Heap session activities: <count>"aus und lösche sie anschließend explizit mitdelete. - Gib nach dem Löschen
"Heap session destroyed"aus
- Erstelle mit geschweiften Klammern
Diese Aufgabe zeigt die beiden wichtigsten Arten, wie Destruktoren aufgerufen werden: automatisch, wenn Objekte auf dem Stack ihren Gültigkeitsbereich verlassen, und manuell, wenn du Objekte auf dem Heap löschst. Beide Wege sollten das dynamisch zugewiesene Aktivitätsprotokoll ordnungsgemäß freigeben, um Speicherlecks zu verhindern.
Binde deine Header-Datei in main.cpp mit #include "Session.h" ein.
Probier es selbst
#include <iostream>
#include <string>
#include "Session.h"
using namespace std;
int main() {
// Eingabe lesen
string username;
int logSize;
getline(cin, username);
cin >> logSize;
// TODO: Erstelle einen Scope-Block mit geschweiften Klammern { }
// Innerhalb des Blocks:
// - Erstelle eine stack-allokierte Session mit dem eingegebenen Benutzernamen, der Session-ID 101 und der eingegebenen Log-Größe
// - Protokolliere zwei Aktivitäten mit den Codes 1 und 2
// - Print "Stack session activities: <count>"
// Wenn der Block endet, wird der Destruktor automatisch ausgeführt
// TODO: After the block, print "Stack session destroyed"
// TODO: Erstelle eine heap-allokierte Session mit new
// - Benutzername: "Guest", Session-ID: 202, Log-Größe: 3
// - Protokolliere eine Aktivität mit dem Code 5
// - Print "Heap session activities: <count>"
// - Lösche die Session
// TODO: After deletion, print "Heap session destroyed"
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 OOP
Externe DateienC++ Build & KompilierungHeader-Dateien & QuelldateienNamespaces & GültigkeitsbereichEinführung in OOP mit C++Klassen vs. ObjekteDer „this“-ZeigerMethoden (Member-Funktionen)Attribute (Datenmember)Grundlagen zu Ctors & DtorsRückblick – Einfacher Taschenrechner4Klassenattribute
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen und -KlassenZusammenfassung – Bankkontoverwaltung7Vererbung
Grundlagen der VererbungZugriffsebenen bei der VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick – Mitarbeiterhierarchie2Speicherverwaltung
Stack- vs. Heap-SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Intelligente Zeiger in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsbezeichner in C++Zugriffsbezeichner im DetailInformationsverbergungStruct vs. KlasseVerschachtelte und innere KlassenWiederholung – Studierendenverwaltungssystem8Polymorphie
Polymorphie zur Compilezeit vs. LaufzeitFunktionsüberladungVirtuelle Funktionen erneut betrachtetRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIRückblick – Shape-Calculator3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorMove-KonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktor im DetailDrei-/Fünf-/Null-RegelZusammenfassung – String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladung der Operatoren [] und ()TypkonvertierungsoperatorenWiederholung – Matrix-Klasse9Templates
FunktionstemplatesKlassen-TemplatesTemplate-SpezialisierungVariadische TemplatesGrundlagen zu SFINAE und Type TraitsRückblick – Generischer ContainerÜbe selbstständig: Online-C++-Compiler