Dynamische Speicherzuweisung in C++

C++C++Beginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab werden Sie lernen, wie Sie dynamische Speicherzuweisung in C++ handhaben. Sie beginnen damit, Speicher mit dem new-Operator zuzuweisen und geben ihn anschließend mit dem delete-Operator wieder frei. Sie werden auch die Erstellung dynamischer Arrays untersuchen, intelligente Zeiger wie shared_ptr und unique_ptr verwenden und auf Speicherlecks prüfen. Diese Fähigkeiten sind für eine effektive Speicherverwaltung in der C++-Programmierung unerlässlich.

Das Lab behandelt die folgenden Schlüsselpunkte: Zuweisen von Speicher mit dem new-Operator, Freigeben von Speicher mit dem delete-Operator, Erstellen dynamischer Arrays mit new[], Löschen von Arrays mit delete[], Implementieren des shared_ptr-Smartpointers, Verwenden von unique_ptr für exklusiven Besitz, Prüfen auf Speicherlecks und Behandeln von Fehlern bei der Speicherzuweisung.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL cpp(("C++")) -.-> cpp/AdvancedConceptsGroup(["Advanced Concepts"]) cpp(("C++")) -.-> cpp/BasicsGroup(["Basics"]) cpp(("C++")) -.-> cpp/OOPGroup(["OOP"]) cpp/BasicsGroup -.-> cpp/arrays("Arrays") cpp/OOPGroup -.-> cpp/classes_objects("Classes/Objects") cpp/OOPGroup -.-> cpp/constructors("Constructors") cpp/AdvancedConceptsGroup -.-> cpp/pointers("Pointers") cpp/AdvancedConceptsGroup -.-> cpp/exceptions("Exceptions") subgraph Lab Skills cpp/arrays -.-> lab-446081{{"Dynamische Speicherzuweisung in C++"}} cpp/classes_objects -.-> lab-446081{{"Dynamische Speicherzuweisung in C++"}} cpp/constructors -.-> lab-446081{{"Dynamische Speicherzuweisung in C++"}} cpp/pointers -.-> lab-446081{{"Dynamische Speicherzuweisung in C++"}} cpp/exceptions -.-> lab-446081{{"Dynamische Speicherzuweisung in C++"}} end

Speicher mit dem new-Operator zuweisen

In diesem Schritt lernen Sie, wie Sie den new-Operator in C++ verwenden, um Speicher dynamisch zur Laufzeit zuzuweisen. Die dynamische Speicherzuweisung ermöglicht es Ihnen, Variablen und Arrays zu erstellen, deren Größe während der Programmausführung bestimmt wird. Dies bietet mehr Flexibilität im Vergleich zur statischen Speicherzuweisung.

Öffnen Sie die WebIDE und erstellen Sie eine neue Datei namens dynamic_memory.cpp im Verzeichnis ~/project:

touch ~/project/dynamic_memory.cpp

Fügen Sie den folgenden Code in die Datei dynamic_memory.cpp ein:

#include <iostream>

int main() {
    // Dynamisch einen Integer mit new zuweisen
    int* dynamicInteger = new int;

    // Einen Wert dem dynamisch zugewiesenen Integer zuweisen
    *dynamicInteger = 42;

    // Den Wert des dynamisch zugewiesenen Integers ausgeben
    std::cout << "Dynamisch zugewiesener Integer-Wert: " << *dynamicInteger << std::endl;

    // Die Speicheradresse des dynamisch zugewiesenen Integers ausgeben
    std::cout << "Speicheradresse: " << dynamicInteger << std::endl;

    return 0;
}

Lassen Sie uns die wichtigsten Konzepte analysieren:

  1. int* dynamicInteger = new int;:

    • Der new-Operator weist Speicher für einen Integer zu.
    • Gibt einen Zeiger auf den zugewiesenen Speicher zurück.
    • Erstellt die Variable auf dem Heap, nicht auf dem Stack.
  2. *dynamicInteger = 42;:

    • Verwendet den Dereferenzierungsoperator *, um einen Wert zuzuweisen.
    • Speichert den Wert 42 im dynamisch zugewiesenen Speicher.

Kompilieren und führen Sie das Programm aus:

g++ dynamic_memory.cpp -o dynamic_memory
./dynamic_memory

Beispielausgabe:

Dynamisch zugewiesener Integer-Wert: 42
Speicheradresse: 0x55f4e8a042a0

Wichtige Punkte zum new-Operator:

  • Weist Speicher dynamisch zur Laufzeit zu.
  • Gibt einen Zeiger auf den zugewiesenen Speicher zurück.
  • Der Speicher wird auf dem Heap zugewiesen.
  • Die Größe kann zur Laufzeit bestimmt werden.
  • Ermöglicht eine flexiblere Speicherverwaltung.

Hinweis: In den nächsten Schritten lernen Sie, wie Sie diesen dynamisch zugewiesenen Speicher richtig freigeben, um Speicherlecks zu vermeiden.

Speicher mit dem delete-Operator freigeben

In diesem Schritt lernen Sie, wie Sie den delete-Operator verwenden, um dynamisch zugewiesenen Speicher in C++ richtig freizugeben. Wenn Sie den Speicher nicht freigeben, kann dies zu Speicherlecks führen, die Leistungsprobleme in Ihrem Programm verursachen können.

Öffnen Sie die WebIDE und erstellen Sie eine neue Datei namens memory_release.cpp im Verzeichnis ~/project:

touch ~/project/memory_release.cpp

Fügen Sie den folgenden Code in die Datei memory_release.cpp ein:

#include <iostream>

int main() {
    // Dynamisch einen Integer zuweisen
    int* dynamicInteger = new int;

    // Einen Wert dem dynamisch zugewiesenen Integer zuweisen
    *dynamicInteger = 42;

    // Den Wert vor der Freigabe des Speichers ausgeben
    std::cout << "Wert vor Freigabe: " << *dynamicInteger << std::endl;

    // Den dynamisch zugewiesenen Speicher mit delete freigeben
    delete dynamicInteger;

    // Den Zeiger nach der Löschung auf nullptr setzen
    dynamicInteger = nullptr;

    // Demonstrieren Sie die sichere Verwendung des Zeigers
    if (dynamicInteger == nullptr) {
        std::cout << "Speicher wurde erfolgreich freigegeben" << std::endl;
    }

    return 0;
}

Wichtige Punkte zum delete-Operator:

  1. delete dynamicInteger;:

    • Gibt den zuvor mit new zugewiesenen Speicher frei.
    • Vermeidet Speicherlecks.
    • Gibt den Speicher an das System zurück.
  2. dynamicInteger = nullptr;:

    • Setzt den Zeiger nach der Löschung auf nullptr.
    • Hilft, versehentliche Verwendung von freigegebenem Speicher zu vermeiden.
    • Bietet eine zusätzliche Sicherheitsüberprüfung.

Kompilieren und führen Sie das Programm aus:

g++ memory_release.cpp -o memory_release
./memory_release

Beispielausgabe:

Wert vor Freigabe: 42
Speicher wurde erfolgreich freigegeben

Wichtige Regeln für die Speicherverwaltung:

  • Verwenden Sie immer delete für Speicher, der mit new zugewiesen wurde.
  • Setzen Sie Zeiger nach der Löschung auf nullptr.
  • Verwenden Sie einen Zeiger nie nach seiner Löschung.
  • Jeder new-Aufruf sollte einen entsprechenden delete-Aufruf haben.

Dynamische Arrays mit new[] erstellen

In diesem Schritt lernen Sie, wie Sie dynamische Arrays mit dem new[]-Operator in C++ erstellen. Dynamische Arrays ermöglichen es Ihnen, zur Laufzeit Speicher für mehrere Elemente zuzuweisen und bieten damit mehr Flexibilität als statische Arrays.

Öffnen Sie die WebIDE und erstellen Sie eine neue Datei namens dynamic_array.cpp im Verzeichnis ~/project:

touch ~/project/dynamic_array.cpp

Fügen Sie den folgenden Code in die Datei dynamic_array.cpp ein:

#include <iostream>

int main() {
    // Deklarieren Sie die Größe des dynamischen Arrays
    int arraySize = 5;

    // Erstellen Sie ein dynamisches Integer-Array mit new[]
    int* dynamicArray = new int[arraySize];

    // Initialisieren Sie die Array-Elemente
    for (int i = 0; i < arraySize; ++i) {
        dynamicArray[i] = i * 10;
    }

    // Geben Sie die Array-Elemente aus
    std::cout << "Inhalt des dynamischen Arrays:" << std::endl;
    for (int i = 0; i < arraySize; ++i) {
        std::cout << "Element " << i << ": " << dynamicArray[i] << std::endl;
    }

    return 0;
}

Wichtige Punkte zu dynamischen Arrays:

  1. int* dynamicArray = new int[arraySize];:

    • Weist Speicher für ein Array von Integern zu.
    • arraySize bestimmt die Anzahl der Elemente.
    • Der Speicher wird auf dem Heap zugewiesen.
    • Die Größe kann zur Laufzeit bestimmt werden.
  2. Array-Initialisierung und -Zugriff:

    • Verwenden Sie die Standard-Array-Indizierung dynamicArray[i].
    • Kann wie ein normales Array manipuliert werden.
    • Ermöglicht eine dynamische Größenbestimmung basierend auf Laufzeitbedingungen.

Kompilieren und führen Sie das Programm aus:

g++ dynamic_array.cpp -o dynamic_array
./dynamic_array

Beispielausgabe:

Inhalt des dynamischen Arrays:
Element 0: 0
Element 1: 10
Element 2: 20
Element 3: 30
Element 4: 40

Wichtige Überlegungen:

  • Dynamische Arrays bieten Flexibilität bei der Speicherzuweisung.
  • Die Größe kann zur Laufzeit bestimmt werden.
  • Denken Sie daran, new[] für die Zuweisung und delete[] für die Freigabe zu verwenden.
  • Passen Sie immer die Zuweisungs- und Freigabemethoden aneinander an.

Arrays mit delete[] löschen

In diesem Schritt lernen Sie, wie Sie den für dynamische Arrays zugewiesenen Speicher richtig mit dem delete[]-Operator freigeben. Eine korrekte Speicherverwaltung ist entscheidend, um Speicherlecks zu vermeiden und eine effiziente Ressourcennutzung zu gewährleisten.

Öffnen Sie die WebIDE und erstellen Sie eine neue Datei namens delete_array.cpp im Verzeichnis ~/project:

touch ~/project/delete_array.cpp

Fügen Sie den folgenden Code in die Datei delete_array.cpp ein:

#include <iostream>

int main() {
    // Deklarieren Sie die Größe des dynamischen Arrays
    int arraySize = 5;

    // Erstellen Sie ein dynamisches Integer-Array mit new[]
    int* dynamicArray = new int[arraySize];

    // Initialisieren Sie die Array-Elemente
    for (int i = 0; i < arraySize; ++i) {
        dynamicArray[i] = i * 10;
    }

    // Geben Sie die Array-Elemente vor der Löschung aus
    std::cout << "Inhalt des Arrays vor der Löschung:" << std::endl;
    for (int i = 0; i < arraySize; ++i) {
        std::cout << "Element " << i << ": " << dynamicArray[i] << std::endl;
    }

    // Geben Sie das dynamisch zugewiesene Array mit delete[] frei
    delete[] dynamicArray;

    // Setzen Sie den Zeiger nach der Löschung auf nullptr
    dynamicArray = nullptr;

    // Demonstrieren Sie die sichere Verwendung des Zeigers
    if (dynamicArray == nullptr) {
        std::cout << "Dynamisches Array wurde erfolgreich gelöscht" << std::endl;
    }

    return 0;
}

Wichtige Punkte zum Löschen dynamischer Arrays:

  1. delete[] dynamicArray;:

    • Gibt den Speicher für das gesamte Array richtig frei.
    • Muss delete[] für Arrays verwenden, die mit new[] zugewiesen wurden.
    • Vermeidet Speicherlecks.
    • Ruft den Destruktor für jedes Array-Element auf.
  2. dynamicArray = nullptr;:

    • Setzt den Zeiger nach der Löschung auf nullptr.
    • Vermeidet versehentlichen Zugriff auf freigegebenen Speicher.
    • Bietet eine zusätzliche Sicherheitsüberprüfung.

Kompilieren und führen Sie das Programm aus:

g++ delete_array.cpp -o delete_array
./delete_array

Beispielausgabe:

Inhalt des Arrays vor der Löschung:
Element 0: 0
Element 1: 10
Element 2: 20
Element 3: 30
Element 4: 40
Dynamisches Array wurde erfolgreich gelöscht

Wichtige Regeln für die Speicherverwaltung:

  • Verwenden Sie immer delete[] für Arrays, die mit new[] zugewiesen wurden.
  • Vermischen Sie nie delete und delete[].
  • Setzen Sie Zeiger nach der Löschung auf nullptr.
  • Jeder new[]-Aufruf sollte einen entsprechenden delete[]-Aufruf haben.

Implementierung des Smart Pointers shared_ptr

In diesem Schritt lernen Sie über shared_ptr, einen Smart Pointer aus der C++ Standardbibliothek, der automatische Speicherverwaltung und Referenzzählung bietet. Smart Pointer helfen, Speicherlecks zu vermeiden und vereinfachen die Speicherverwaltung.

Öffnen Sie die WebIDE und erstellen Sie eine neue Datei namens shared_pointer.cpp im Verzeichnis ~/project:

touch ~/project/shared_pointer.cpp

Fügen Sie den folgenden Code in die Datei shared_pointer.cpp ein:

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass(int value) : data(value) {
        std::cout << "Konstruktor aufgerufen. Wert: " << data << std::endl;
    }

    ~MyClass() {
        std::cout << "Destruktor aufgerufen. Wert: " << data << std::endl;
    }

    int getData() const { return data; }

private:
    int data;
};

int main() {
    // Erstellen Sie einen shared_ptr für MyClass
    std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(42);

    // Erstellen Sie einen weiteren shared_ptr, der auf dasselbe Objekt zeigt
    std::shared_ptr<MyClass> ptr2 = ptr1;

    // Geben Sie die Referenzzählung aus
    std::cout << "Referenzzählung: " << ptr1.use_count() << std::endl;

    // Greifen Sie auf das Objekt über den shared_ptr zu
    std::cout << "Daten von ptr1: " << ptr1->getData() << std::endl;
    std::cout << "Daten von ptr2: " << ptr2->getData() << std::endl;

    // Die Pointer geben den Speicher automatisch frei, wenn sie aus dem Gültigkeitsbereich gehen
    return 0;
}

Wichtige Punkte zu shared_ptr:

  1. std::make_shared<MyClass>(42):

    • Erstellt einen Shared Pointer mit dynamischer Speicherzuweisung.
    • Initialisiert das Objekt mit einem Konstruktor-Argument.
    • Ist effizienter als die separate Erstellung von new und shared_ptr.
  2. ptr1.use_count():

    • Gibt die Anzahl der shared_ptr-Instanzen zurück, die auf dasselbe Objekt zeigen.
    • Hilft, die Referenzzählung des Objekts zu verfolgen.
  3. Automatische Speicherverwaltung:

    • Der Speicher wird automatisch freigegeben, wenn kein shared_ptr mehr auf das Objekt verweist.
    • Vermeidet Fehler bei der manuellen Speicherverwaltung.

Kompilieren und führen Sie das Programm aus:

g++ -std=c++11 shared_pointer.cpp -o shared_pointer
./shared_pointer

Beispielausgabe:

Konstruktor aufgerufen. Wert: 42
Referenzzählung: 2
Daten von ptr1: 42
Daten von ptr2: 42
Destruktor aufgerufen. Wert: 42

Wichtige Eigenschaften von shared_ptr:

  • Automatische Speicherverwaltung
  • Referenzzählung
  • Vermeidung von Speicherlecks
  • Thread-sichere Referenzzählung

Verwendung von unique_ptr für exklusive Besitzrechte

In diesem Schritt lernen Sie über unique_ptr, einen Smart Pointer, der exklusive Besitzrechte an dynamisch zugewiesenen Ressourcen gewährt. Im Gegensatz zu shared_ptr stellt unique_ptr sicher, dass nur ein einziger Pointer zur gleichen Zeit die Ressource besitzen kann.

Öffnen Sie die WebIDE und erstellen Sie eine neue Datei namens unique_pointer.cpp im Verzeichnis ~/project:

touch ~/project/unique_pointer.cpp

Fügen Sie den folgenden Code in die Datei unique_pointer.cpp ein:

#include <iostream>
#include <memory>

class Resource {
public:
    Resource(int value) : data(value) {
        std::cout << "Ressource erstellt. Wert: " << data << std::endl;
    }

    ~Resource() {
        std::cout << "Ressource zerstört. Wert: " << data << std::endl;
    }

    int getData() const { return data; }

private:
    int data;
};

void processResource(std::unique_ptr<Resource> resource) {
    std::cout << "Verarbeitung der Ressource mit Wert: " << resource->getData() << std::endl;
    // Die Ressource wird automatisch gelöscht, wenn die Funktion endet
}

int main() {
    // Erstellen Sie einen unique_ptr
    std::unique_ptr<Resource> ptr1 = std::make_unique<Resource>(42);

    // Geben Sie die Ressourcendaten aus
    std::cout << "Ressourcenwert: " << ptr1->getData() << std::endl;

    // Übertragen Sie die Besitzrechte mit std::move
    std::unique_ptr<Resource> ptr2 = std::move(ptr1);

    // ptr1 ist jetzt nullptr
    if (ptr1 == nullptr) {
        std::cout << "ptr1 ist nach Übertragung der Besitzrechte null" << std::endl;
    }

    // Übergeben Sie den unique_ptr an eine Funktion (Besitzrechte werden übertragen)
    processResource(std::move(ptr2));

    return 0;
}

Wichtige Punkte zu unique_ptr:

  1. std::make_unique<Resource>(42):

    • Erstellt einen Unique Pointer mit dynamischer Speicherzuweisung.
    • Stellt exklusive Besitzrechte an der Ressource sicher.
  2. std::move(ptr1):

    • Übertragt die Besitzrechte an der Ressource.
    • Der ursprüngliche Pointer wird nullptr.
    • Verhindert, dass mehrere Pointer dieselbe Ressource besitzen.
  3. Automatische Speicherverwaltung:

    • Die Ressource wird automatisch gelöscht, wenn der unique_ptr aus dem Gültigkeitsbereich geht.
    • Keine manuelle Speicherverwaltung erforderlich.

Kompilieren und führen Sie das Programm aus:

g++ -std=c++14 unique_pointer.cpp -o unique_pointer
./unique_pointer

Beispielausgabe:

Ressource erstellt. Wert: 42
Ressourcenwert: 42
ptr1 ist nach Übertragung der Besitzrechte null
Verarbeitung der Ressource mit Wert: 42
Ressource zerstört. Wert: 42

Wichtige Eigenschaften von unique_ptr:

  • Exklusive Besitzrechte
  • Automatische Speicherverwaltung
  • Kann nicht kopiert, nur verschoben werden
  • Verhindert Ressourcenlecks

Prüfen auf Speicherlecks

In diesem Schritt lernen Sie, wie Sie Speicherlecks in C++ mit Valgrind, einem leistungsstarken Speicher-Debugging-Tool, erkennen und vermeiden können. Speicherlecks treten auf, wenn dynamisch zugewiesener Speicher nicht richtig freigegeben wird, was dazu führt, dass Ihr Programm immer mehr Speicher verbraucht.

Zuerst installieren Sie Valgrind im Terminal:

sudo apt update
sudo apt install -y valgrind

Erstellen Sie ein Beispiel für ein Speicherleck in der WebIDE, indem Sie memory_leak.cpp im Verzeichnis ~/project erstellen:

touch ~/project/memory_leak.cpp

Fügen Sie den folgenden Code in die Datei memory_leak.cpp ein:

#include <iostream>

class Resource {
public:
    Resource(int value) : data(value) {
        std::cout << "Ressource erstellt: " << data << std::endl;
    }

    ~Resource() {
        std::cout << "Ressource zerstört: " << data << std::endl;
    }

private:
    int data;
};

void createMemoryLeak() {
    // Dies erzeugt ein Speicherleck, da die Ressource nicht gelöscht wird
    Resource* leak = new Resource(42);
    // Fehlt: delete leak;
}

int main() {
    // Simulieren Sie mehrere Speicherlecks
    for (int i = 0; i < 3; ++i) {
        createMemoryLeak();
    }

    return 0;
}

Kompilieren Sie das Programm mit Debugging-Symbolen:

g++ -g memory_leak.cpp -o memory_leak

Führen Sie Valgrind aus, um Speicherlecks zu erkennen:

valgrind --leak-check=full./memory_leak

Beispielausgabe von Valgrind:

==1988== Memcheck, a memory error detector
==1988== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1988== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==1988== Command:./memory_leak
==1988==
Ressource erstellt: 42
Ressource erstellt: 42
Ressource erstellt: 42
==1988==
==1988== HEAP SUMMARY:
==1988==     in use at exit: 12 bytes in 3 blocks
==1988==   total heap usage: 5 allocs, 2 frees, 73,740 bytes allocated
==1988==
==1988== 12 bytes in 3 blocks are definitely lost in loss record 1 of 1
==1988==    at 0x4849013: operator new(unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==1988==    by 0x109241: createMemoryLeak() (memory_leak.cpp:19)
==1988==    by 0x109299: main (memory_leak.cpp:26)
==1988==
==1988== LEAK SUMMARY:
==1988==    definitely lost: 12 bytes in 3 blocks
==1988==    indirectly lost: 0 bytes in 0 blocks
==1988==      possibly lost: 0 bytes in 0 blocks
==1988==    still reachable: 0 bytes in 0 blocks
==1988==         suppressed: 0 bytes in 0 blocks
==1988==
==1988== For lists of detected and suppressed errors, rerun with: -s
==1988== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Wie Sie sehen können, hat Valgrind ein Speicherleck von 12 Bytes in 3 Blöcken erkannt. Das in createMemoryLeak() erstellte Resource-Objekt wurde nicht gelöscht, was das Speicherleck verursacht.

Um das Speicherleck zu beheben, ändern Sie den Code so, dass die Ressourcen richtig gelöscht werden:

void createMemoryLeak() {
    // Löschen Sie die dynamisch zugewiesene Ressource richtig
    Resource* leak = new Resource(42);
    delete leak;  // Fügen Sie diese Zeile hinzu, um Speicherlecks zu vermeiden
}

Kompilieren und führen Sie das Programm erneut mit Valgrind aus, um zu überprüfen, ob das Speicherleck behoben ist:

g++ -g memory_leak.cpp -o memory_leak
valgrind --leak-check=full./memory_leak
==2347== Memcheck, a memory error detector
==2347== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2347== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==2347== Command:./memory_leak
==2347==
Ressource erstellt: 42
Ressource zerstört: 42
Ressource erstellt: 42
Ressource zerstört: 42
Ressource erstellt: 42
Ressource zerstört: 42
==2347==
==2347== HEAP SUMMARY:
==2347==     in use at exit: 0 bytes in 0 blocks
==2347==   total heap usage: 5 allocs, 5 frees, 73,740 bytes allocated
==2347==
==2347== All heap blocks were freed -- no leaks are possible
==2347==
==2347== For lists of detected and suppressed errors, rerun with: -s
==2347== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Wichtige Punkte zu Speicherlecks:

  • Löschen Sie immer dynamisch zugewiesenen Speicher mit delete.
  • Verwenden Sie Smart Pointer wie unique_ptr und shared_ptr.
  • Verwenden Sie Valgrind, um Speicherlecks zu erkennen.
  • Kompilieren Sie mit der -g-Option für bessere Debugging-Informationen.

Umgang mit Speicherzuweisungsfehlern

In diesem Schritt lernen Sie, wie Sie Speicherzuweisungsfehler in C++ behandeln können. Wenn die dynamische Speicherzuweisung fehlschlägt, wirft der new-Operator eine std::bad_alloc-Ausnahme, die Sie fangen und elegant behandeln können.

Öffnen Sie die WebIDE und erstellen Sie eine neue Datei namens memory_allocation.cpp im Verzeichnis ~/project:

touch ~/project/memory_allocation.cpp

Fügen Sie den folgenden Code in die Datei memory_allocation.cpp ein:

#include <iostream>
#include <new>
#include <limits>

void demonstrateMemoryAllocation() {
    try {
        // Versuchen Sie, eine große Menge an Speicher zuzuweisen
        const size_t largeSize = 1000000000000; // 1 Billion Integer
        int* largeArray = new int[largeSize];

        // Diese Zeile wird nicht erreicht, wenn die Zuweisung fehlschlägt
        std::cout << "Speicherzuweisung erfolgreich" << std::endl;

        // Geben Sie den zugewiesenen Speicher frei
        delete[] largeArray;
    }
    catch (const std::bad_alloc& e) {
        // Behandeln Sie den Speicherzuweisungsfehler
        std::cerr << "Speicherzuweisung fehlgeschlagen: " << e.what() << std::endl;
    }
}

void safeMemoryAllocation() {
    // Verwenden Sie std::nothrow, um das Werfen von Ausnahmen zu verhindern
    int* safeArray = new(std::nothrow) int[1000000];

    if (safeArray == nullptr) {
        std::cerr << "Speicherzuweisung stumm fehlgeschlagen" << std::endl;
        return;
    }

    // Verwenden Sie den zugewiesenen Speicher
    std::cout << "Sichere Speicherzuweisung erfolgreich" << std::endl;

    // Geben Sie den zugewiesenen Speicher frei
    delete[] safeArray;
}

int main() {
    std::cout << "Demonstration des Umgangs mit Speicherzuweisungsfehlern:" << std::endl;

    // Methode 1: Verwendung von Ausnahmebehandlung
    demonstrateMemoryAllocation();

    // Methode 2: Verwendung von std::nothrow
    safeMemoryAllocation();

    return 0;
}

Wichtige Punkte zum Umgang mit Speicherzuweisungsfehlern:

  1. Ausnahmebehandlung mit std::bad_alloc:

    • Ein try-catch-Block fängt Speicherzuweisungsausnahmen auf.
    • Liefert detaillierte Fehlerinformationen.
    • Verhindert Abstürze des Programms.
  2. Speicherzuweisung mit std::nothrow:

    • Verhindert das Werfen von Ausnahmen.
    • Gibt nullptr bei einer fehlgeschlagenen Zuweisung zurück.
    • Ermöglicht die stumme Behandlung von Fehlern.

Kompilieren und führen Sie das Programm aus:

g++ memory_allocation.cpp -o memory_allocation
./memory_allocation

Beispielausgabe:

Demonstration des Umgangs mit Speicherzuweisungsfehlern:
Speicherzuweisung fehlgeschlagen: std::bad_alloc
Sichere Speicherzuweisung erfolgreich

Wichtige Strategien für die Speicherzuweisung:

  • Prüfen Sie immer auf Zuweisungsfehler.
  • Verwenden Sie Ausnahmebehandlung oder std::nothrow.
  • Implementieren Sie Fallback-Mechanismen.
  • Vermeiden Sie die Zuweisung extrem großer Speicherblöcke.

Zusammenfassung

In diesem Lab lernen Sie, wie Sie die dynamische Speicherzuweisung in C++ handhaben können. Zunächst lernen Sie, den new-Operator zu verwenden, um Speicher zur Laufzeit dynamisch zuzuweisen. Dies ermöglicht eine flexiblere Speicherverwaltung im Vergleich zur statischen Zuweisung. Anschließend lernen Sie, wie Sie diesen dynamisch zugewiesenen Speicher richtig mit dem delete-Operator freigeben, um Speicherlecks zu vermeiden. Darüber hinaus werden Sie die Erstellung dynamischer Arrays mit new[] und deren Löschung mit delete[] untersuchen. Das Lab behandelt auch die Verwendung von Smart Pointern wie shared_ptr und unique_ptr, um die Speicherverwaltung zu vereinfachen und häufige Fallstricke zu vermeiden. Schließlich lernen Sie Techniken kennen, um Speicherzuweisungsfehler zu erkennen und zu behandeln.