Wird geladen...

Dynamische Speicherverwaltung: new und delete

Heap-Zuweisungen, sicheres new/delete und erste Schritte in Richtung RAII.

In C++ ist der Speicher in zwei Hauptbereiche unterteilt: Stack (Stapelspeicher) und Heap (dynamischer Speicher). Während der Stack automatisch verwaltet wird, wird der Speicher im Heap manuell vom Programmierer kontrolliert. Dynamische Speicherverwaltung wird verwendet, um während der Programmausführung Speicher zu reservieren und wieder freizugeben. In diesem Artikel lernen wir die Verwendung von new und delete zur dynamischen Speicherverwaltung im Detail kennen.


1. Unterschied zwischen Stack und Heap

EigenschaftStack (Automatisch)Heap (Dynamisch)
VerwaltungAutomatisch (vom Compiler)Manuell (vom Programmierer)
LebensdauerWird automatisch gelöscht, wenn die Funktion endetBleibt bestehen, bis sie manuell gelöscht wird
GeschwindigkeitSehr schnellLangsamer (dynamische Verwaltung)
SpeichergrößeBegrenztGrößer
VerwendungLokale VariablenDynamische Objekte, Arrays

2. Speicherreservierung mit dem Schlüsselwort new

Der Operator new reserviert dynamisch Speicher im Heap und gibt die Adresse des reservierten Bereichs zurück. Diese Adresse wird normalerweise einer Pointer-Variablen zugewiesen.


#include <iostream>
using namespace std;

int main() {
    int *ptr = new int; // Speicher für eine int-Variable reservieren
    *ptr = 42;
    cout << "Wert: " << *ptr << endl;

    delete ptr; // Speicher freigeben
    ptr = nullptr; // Zeiger sicher machen
}

Hinweis: Speicher, der mit new reserviert wurde, muss mit delete manuell freigegeben werden. Andernfalls entsteht ein Speicherleck (memory leak).


3. Dynamische Arrays mit new

Um ein dynamisches Array zu erstellen, wird new[] verwendet. Die Größe kann zur Laufzeit bestimmt werden.


#include <iostream>
using namespace std;

int main() {
    int n;
    cout << "Wie viele Elemente soll das Array haben? ";
    cin >> n;

    int *array = new int[n]; // Array mit n Elementen erstellen

    for (int i = 0; i < n; i++)
        array[i] = (i + 1) * 10;

    cout << "Array: ";
    for (int i = 0; i < n; i++)
        cout << array[i] << " ";

    delete[] array; // Speicher freigeben
    array = nullptr;
}

Die Verwendung von delete[] ist wichtig; das normale delete gilt nur für einzelne Variablen, nicht für Arrays.


4. Schritte der dynamischen Speicherverwaltung

  1. new → Reserviert Speicher im Heap.
  2. Pointer → Speichert die Adresse des reservierten Speichers.
  3. Daten werden verarbeitet oder gefüllt.
  4. delete / delete[] → Gibt den Speicher frei.
  5. Pointer = nullptr → Verhindert „dangling pointers“ (hängende Zeiger).

5. Was ist ein Speicherleck (Memory Leak)?

Wenn dynamisch reservierter Speicher nicht freigegeben wird, sammeln sich ungenutzte Speicherbereiche an. Dies nennt man Speicherleck und kann bei langfristig laufenden Programmen zu Leistungsproblemen führen.


void SchlechtesBeispiel() {
    int *p = new int(10);
    // delete p; // Vergessen! Speicherleck
}

Lösung: Speicher immer mit delete freigeben.


6. nullptr und Speichersicherheit

Vor C++11 wurden leere Pointer normalerweise mit NULL dargestellt. In modernem C++ sollte stattdessen das typsichere Schlüsselwort nullptr verwendet werden.


int *p = nullptr;

if (p == nullptr) {
    cout << "Der Pointer zeigt auf keine Adresse." << endl;
}

Die Verwendung von nullptr hilft, ungültige Speicherzugriffe und Segmentation Faults zu vermeiden.


7. Dynamischer Speicher mit Funktionen

Speicher kann dynamisch erstellt und an Funktionen übergeben werden. Diese Technik ist besonders nützlich bei der Arbeit mit dynamischen Arrays.


void Fuellen(int *p, int n) {
    for (int i = 0; i < n; i++)
        p[i] = (i + 1) * 2;
}

int main() {
    int *array = new int[5];
    Fuellen(array, 5);

    for (int i = 0; i < 5; i++)
        cout << array[i] << " ";

    delete[] array;
}

8. Objekte mit new erstellen

new kann nicht nur für Grunddatentypen, sondern auch für Klassenobjekte verwendet werden.


#include <iostream>
using namespace std;

class Student {
public:
    string name;
    Student(string n) : name(n) {
        cout << name << " erstellt." << endl;
    }
    ~Student() {
        cout << name << " gelöscht." << endl;
    }
};

int main() {
    Student *p = new Student("Ali");
    delete p; // Destruktor wird aufgerufen
}

Beim Löschen eines mit new erstellten Objekts wird automatisch der Destruktor der Klasse aufgerufen.


9. Smart Pointer (Moderner C++-Ansatz)

Mit C++11 wurden Smart Pointer als Alternative zur manuellen Speicherfreigabe eingeführt. Sie sorgen für eine automatische Speicherverwaltung.


#include <iostream>
#include <memory>
using namespace std;

int main() {
    unique_ptr<int> p = make_unique<int>(100);
    cout << *p << endl; // 100
}

Smart Pointer geben den Speicher automatisch frei, wenn das Objekt den Gültigkeitsbereich verlässt. Dadurch werden Speicherlecks effektiv vermieden.


10. TL;DR

  • new → Reserviert Speicher im Heap und gibt die Adresse zurück.
  • delete → Gibt Speicher frei (für einzelne Variablen).
  • new[] / delete[] → Wird für dynamische Arrays verwendet.
  • nullptr → Sichere Definition für leere Pointer.
  • Um Speicherlecks zu vermeiden, sollte jedem new ein delete entsprechen.
  • std::unique_ptr und std::shared_ptr sind moderne Alternativen.
  • Alle Beispiele können in Visual Studio 2022 oder GCC 11+ kompiliert werden.

Ähnliche Artikel