C++ Tutorial

Operatoren new und delete

new Operator

new für intrinsische Daten

Der Operator new reserviert zur Programmlaufzeit Speicher und erhält als Operand den Datentyp DTYP, für den Speicher reserviert werden soll. Als Ergebnis liefert new einen Zeiger auf den reservierten Speicherbereich zurück. Dieser zurückgelieferte Zeiger hat den Datentyp DTYP*. Durch die optionale Angabe eines Wertes in einer runden oder geschweiften Klammer kann der reservierte Speicher mit einem Wert initialisiert werden.

1: // main() Funktion
2: int main()
3: {
4:    // Speicher für ein long-Datum reservieren
5:    long *lptr = new long;
6:    // Speicher für ein short-Datum reservieren
7:    // und mit dem Wert 10 initialisieren
8:    short *sptr = new short{10};
9:    // Oder besser mit auto
10:    auto sptr1 = new short{10};
11: }

Kann new nicht den angeforderten Speicher reservieren, wird eine Ausnahme vom Typ bad_alloc ausgelöst und das Programm beendet. Was Ausnahmen sind und wie darauf reagiert werden kann folgt später.

Um Speicher für ein Feld mit intrinsischen Daten zu reservieren, folgt nach dem Datentyp des Feldes innerhalb eckiger Klammern die Angabe der Feldgröße. Optional kann das Feld gleichzeitig mit Daten initialisiert werden, wobei die Feldgröße entfallen kann.

1: // main() Funktion
2: int main()
3: {
4:    // Speicher für ein Feld mit 10 short reservieren
5:    auto ptr1 = new short[10];
6:    // Speicher für 5 long reservieren/initialisieren
7:    auto ptr2 = new long[] {1L,2L,3L,4L,5L};
8: }

new für mehrdimensionale Felder

Die Reservierung von Speicher für mehrdimensionale Felder erfolgt in mehreren Schritten. Zuerst ist Speicher für ein Zeigerfeld zu reservieren. Dieses Zeigerfeld repräsentiert die 'Zeilen' (1. Dimension). Anschließend werden in diesem Zeigerfeld die Adressen der Spaltenfelder (2. Dimension) abgelegt. Sehen wir uns diesen Vorgang Schritt für Schritt an:

1: // Feld mit 3x2 float-Zahlen reservieren
2: constexpr int ROW=3;
3: constexpr int COLUMN=2;
4: // Schritt 1: Zeiger auf Zeiger definieren
5: float **ppArray;
6:
7: // main() Funktion
8: int main()
9: {
10:    // Schritt 2: Zeigerfeld für 3 float-Zeiger reservieren
11:    // Alternativ: auto ppArray = new float*[ROW]
12:    ppArray = new float*[ROW];
13:    // Schritt 3: Spaltenfelder reservieren
14:    for (auto i=0; i<ROW; i++)
15:       ppArray[i] = new float[COLUMN];
16:    // Zugriff auf Feld wie üblich

17:    ppArray[iRow][iCol] = ...;
18: }

Zunächst wird ein Zeiger auf einen Zeiger vom Datentyp des Feldes definiert. Anschließend wird mittels new ein Zeigerfeld mit so vielen Elementen reserviert, wie das Feld Zeilen hat. Zum Schluss werden in einer Schleife die 'Spaltenfelder' reserviert. Die von new zurückgelieferten Adressen werden im reservierten Zeigerfeld abgelegt.

Der Zugriff auf die einzelnen Elemente des mehrdimensionalen Feldes erfolgt in der üblichen Art und Weise (mehrfache Indizierung).

delete Operator

delete für intrinsische Daten und Felder

Die Freigabe des mittels new reservierten Speichers erfolgt mit dem delete Operator. Wurde Speicher für einfache intrinsische Daten (keine Felder) reserviert, erhält delete als Operand den von new zurückgelieferten Zeiger. Wurde dagegen Speicher für ein Feld reserviert, muss nach dem delete Operator zunächst eine leere eckige Klammer stehen und danach der von new zurückgelieferte Zeiger. Wird diese leere eckige Klammer vergessen, meldet der Compiler keinen Fehler! Warum bei der Freigabe des Speichers diese eckigen Klammern trotzdem wichtig sind, erfahren Sie im nächsten Kapitel über dynamische Objekte. Vergessen Sie daher niemals die eckigen Klammern beim Löschen von Feldern.

1: int main()
2: {
3:    // long reservieren und wieder freigeben
4:    auto pData = new long;
5:    ...
6:    delete pData;
7:    // char-Feld reservieren und wieder freigeben
8:    auto pArray = new char[30];
9:    ...
10:   delete [] pArray;
11: }

delete für mehrdimensionale Felder

Bei der Freigabe des Speichers für mehrdimensionale Felder ist die Reihenfolge der Reservierungen umzudrehen, d.h., es wird zuerst der Speicher für die Spaltenfelder freigegeben und zum Schluss der Speicher für das Zeigerfeld. Beachten Sie beim delete Operator die leeren eckigen Klammern. Sie haben es hier mit Feldern zu tun!

1: // Feld mit 3x2 float Elementen
2: const int ROW=3;
3: const int COLUMN=2;
4: // Schritt 1: Zeiger auf Zeiger definieren
5: float **ppArray;
6:
7: // main() Funktion
8: int main()
9: {
10:    // Reservierung des 2-dimimensionalen Feldes
11:    ...
12:    // Zuerst Spaltenfelder freigeben
13:    for (auto i=0; i<ROW; i++)
14:       delete [] ppArray[i];
15:    // Und Zeigerfeld freigeben
16:    delete [] ppArray;
17: }
1: // Feld mit 3x2 float Elementen
2: const int ROW=3;
3: const int COLUMN=2;
4: // Schritt 1: Zeiger auf Zeiger definieren
5: float **ppArray;
6:
7: // main() Funktion
8: int main()
9: {
10:    // Reservierung des 2-dimimensionalen Feldes
11:    ...
12:    // Zuerst Spaltenfelder freigeben
13:    for (auto i=0; i<ROW; i++)
14:       delete [] ppArray[i];
15:    // Und Zeigerfeld freigeben
16:    delete [] ppArray;
17: }

Und noch ein Hinweis: Es ist erlaubt, den delete Operator mit einem nullptr aufzurufen oder mit einem Zeiger, dessen Inhalt 0 ist (aus historischen Gründen). In diesem Fall führt der delete Operator nichts aus.


Copyright 2024 © Wolfgang Schröder
E-Mail mit Fragen oder Kommentaren zu dieser Website an: info@cpp-tutor.de
Impressum & Datenschutz