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
EinfachLass uns ein einfaches Nachrichtenspeichersystem erstellen, das die dynamische Speicherzuweisung mit new und delete demonstriert.
Du wirst zwei Dateien erstellen, um deinen Code zu organisieren:
MessageBox.h: Definiere eineMessageBox-Klasse, die ein dynamisch verwaltetes Array von Nachrichten verwaltet. Die Klasse sollte Folgendes enthalten:- Ein privates Zeigerattribut auf ein dynamisch zugewiesenes Array von Zeichenketten
- Eine private Ganzzahl, die die aktuelle Anzahl der Nachrichten erfasst
- Eine private Ganzzahl, die die maximale Kapazität speichert
- Einen Konstruktor, der eine Kapazität entgegennimmt und das Array mithilfe von
new[]zuweist - Einen Destruktor, der den Speicher ordnungsgemäß mithilfe von
delete[]freigibt und"MessageBox destroyed"ausgibt - Eine
addMessage(string msg)-Methode, die eine Nachricht hinzufügt, wenn noch Platz vorhanden ist, und bei Erfolgtrueoder bei voller Kapazitätfalsezurückgibt - Eine
printAll()-Methode, die jede gespeicherte Nachricht in einer eigenen Zeile ausgibt
main.cpp: Lies einen Kapazitätswert und eine Anzahl von Nachrichten aus der Eingabe ein. Lies anschließend diese Anzahl an Nachrichten als Zeichenketten ein. Erstelle eineMessageBoxauf dem Heap mithilfe vonnew, füge alle Nachrichten hinzu, rufeprintAll()auf und lösche anschließend die MessageBox ordnungsgemäß, um den Speicher freizugeben.
Das Eingabeformat lautet:
- Erste Zeile: die Kapazität (Ganzzahl)
- Zweite Zeile: die Anzahl der hinzuzufügenden Nachrichten (Ganzzahl)
- Folgende Zeilen: eine Nachricht pro Zeile
Denke daran: Auf jedes new muss ein passendes delete folgen, und auf jedes new[] ein passendes delete[]. Nach dem Löschen ist es gute Praxis, Zeiger auf nullptr zu setzen.
Binde deine Headerdatei in main.cpp mithilfe von #include "MessageBox.h" ein.
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 & 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