Dynamischer Speicher (new/delete)
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 14 von 104.
Nachdem Sie nun Zeiger und Referenzen verstehen, lassen Sie uns diese bei der dynamischen Speicherallokation einsetzen. Die Operatoren new und delete ermöglichen es Ihnen, Objekte zur Laufzeit auf dem Heap zu erstellen und zu zerstören.
Verwenden Sie new, um Speicher zuzuweisen und einen Zeiger darauf zurückzuerhalten:
int* num = new int; // Einzelnen Integer allozieren
*num = 42; // Wert über Zeiger zuweisen
Player* player = new Player("Hero"); // Objekt allozierenJedes new muss ein passendes delete haben, um den Speicher freizugeben:
delete num; // Einzelnes Objekt freigeben
delete player; // Ruft den Destruktor auf und gibt dann den Speicher freiVerwenden Sie für Arrays new[] und delete[]:
int* scores = new int[5]; // Array von 5 Integern reservieren
scores[0] = 100;
delete[] scores; // Array freigeben - beachten Sie die Klammern!Häufige Fehler, die vermieden werden sollten:
// Speicherleck - Löschen vergessen
int* ptr = new int(10);
ptr = new int(20); // Zugriff auf die erste Zuweisung verloren!
// Dangling Pointer - Verwendung nach dem Löschen
delete ptr;
*ptr = 5; // Undefiniertes Verhalten!
// Falsches delete
int* arr = new int[10];
delete arr; // Falsch! Sollte delete[] seinNach dem Löschen sollten Zeiger auf nullptr gesetzt werden, um eine versehentliche Wiederverwendung zu vermeiden. Die manuelle Speicherverwaltung ist fehleranfällig, weshalb modernes C++ Smart Pointer bevorzugt, die wir als Nächstes untersuchen werden.
Aufgabe
EinfachLassen Sie uns ein einfaches Nachrichtenspeichersystem bauen, das die dynamische Speicherallokation mit new und delete demonstriert.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
MessageBox.h: Definieren Sie eineMessageBox-Klasse, die ein Array von Nachrichten dynamisch verwaltet. Die Klasse sollte Folgendes haben:- Einen privaten Pointer auf ein dynamisch allokiertes Array von Strings
- Einen privaten Integer, der die aktuelle Anzahl der Nachrichten verfolgt
- Einen privaten Integer, der die maximale Kapazität speichert
- Einen Konstruktor, der eine Kapazität entgegennimmt und das Array mit
new[]allokiert - Einen Destruktor, der den Speicher ordnungsgemäß mit
delete[]freigibt und"MessageBox destroyed"ausgibt - Eine
addMessage(string msg)-Methode, die eine Nachricht hinzufügt, wenn Platz vorhanden ist, und bei Erfolgtrueoder bei Vollbelegungfalsezurückgibt - Eine
printAll()-Methode, die jede gespeicherte Nachricht in einer eigenen Zeile ausgibt
main.cpp: Lesen Sie einen Kapazitätswert und eine Anzahl von Nachrichten von der Eingabe ein. Lesen Sie dann entsprechend viele Nachrichtenzeichenfolgen ein. Erstellen Sie eineMessageBoxauf dem Heap mitnew, fügen Sie alle Nachrichten hinzu, rufen SieprintAll()auf und löschen Sie die MessageBox anschließend ordnungsgemäß, um Speicher freizugeben.
Das Eingabeformat ist wie folgt:
- Erste Zeile: die Kapazität (Integer)
- Zweite Zeile: die Anzahl der hinzuzufügenden Nachrichten (Integer)
- Folgende Zeilen: eine Nachricht pro Zeile
Denken Sie daran: Jedes new benötigt ein passendes delete, und jedes new[] benötigt ein passendes delete[]. Nach dem Löschen ist es gute Praxis, Pointer auf nullptr zu setzen.
Binden Sie Ihre Header-Datei in main.cpp mit #include "MessageBox.h" ein.
Spickzettel
Verwenden Sie new, um Speicher dynamisch auf dem Heap zu reservieren und einen Zeiger darauf zu erhalten:
int* num = new int; // Einzelnen Integer reservieren
*num = 42; // Wert über Zeiger zuweisen
Player* player = new Player("Hero"); // Objekt reservierenJedem new muss ein passendes delete entsprechen, um den Speicher freizugeben:
delete num; // Einzelnes Objekt freigeben
delete player; // Ruft den Destruktor auf und gibt dann den Speicher freiVerwenden Sie für Arrays new[] und delete[]:
int* scores = new int[5]; // Array von 5 Integern reservieren
scores[0] = 100;
delete[] scores; // Array freigeben - beachten Sie die Klammern!Häufige Fehler, die vermieden werden sollten:
// Speicherleck - delete vergessen
int* ptr = new int(10);
ptr = new int(20); // Zugriff auf die erste Reservierung verloren!
// Dangling Pointer - Verwendung nach delete
delete ptr;
*ptr = 5; // Undefiniertes Verhalten!
// Falsches delete
int* arr = new int[10];
delete arr; // Falsch! Sollte delete[] seinSetzen Sie Zeiger nach dem Löschen auf nullptr, um eine versehentliche Wiederverwendung zu vermeiden.
Probier es selbst
#include <iostream>
#include <string>
#include "MessageBox.h"
using namespace std;
int main() {
int capacity;
int numMessages;
// Kapazität und Anzahl der Nachrichten einlesen
cin >> capacity;
cin >> numMessages;
cin.ignore(); // Den Zeilenumbruch nach der Zahl entfernen
// TODO: Eine MessageBox auf dem Heap mit new erstellen
// TODO: Alle Nachrichten einlesen und zur MessageBox hinzufügen
for (int i = 0; i < numMessages; i++) {
string message;
getline(cin, message);
// Nachricht zur MessageBox hinzufügen
}
// TODO: printAll() aufrufen, um alle Nachrichten anzuzeigen
// TODO: Die MessageBox löschen, um Speicher freizugeben
// Daran denken, den Pointer nach dem Löschen auf nullptr zu setzen
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 & QuelldateienNamensräume & GültigkeitsbereicheEinführung in OOP in C++Klassen vs. ObjekteDer 'this'-PointerMethoden (Elementfunktionen)Attribute (Datenelemente)Grundlagen zu Ctors & DtorsRückblick - Einfacher Taschenrechner4Klasseneigenschaften
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen & KlassenZusammenfassung - Bankkonto-Manager7Vererbung
Grundlagen der VererbungZugriffsstufen bei VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick - Mitarbeiter-Hierarchie2Speicherverwaltung
Stack vs. Heap SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Smart Pointers in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsspezifizierer in C++Zugriffsspezifizierer im DetailInformation HidingStruct vs. ClassVerschachtelte & innere KlassenRückblick - Studentenverwaltungssystem8Polymorphie
Kompilierzeit- vs. Laufzeit-PolymorphieFunktionsüberladungVirtuelle Funktionen – WiederholungRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIZusammenfassung – Formen-Rechner3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorVerschiebekonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktoren im DetailRule of Three / Five / ZeroZusammenfassung - String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladen der [] und () OperatorenTypumwandlungsoperatorenRückblick - Matrix-Klasse9Templates
FunktionstemplatesKlassentemplatesTemplate-SpezialisierungVariadische TemplatesSFINAE & Type Traits GrundlagenRückblick - Generische Container