Assignment Chef icon Assignment Chef
All German tutorials

Programming lesson

C++ Chain-Klasse selbst erstellen: Vektor-Klon mit Big Five, Move-Semantik und dynamischem Array

Lerne, wie du in C++ eine eigene Chain-Klasse baust – ähnlich wie std::vector, aber ganz ohne STL. Inklusive Big Five, Move-Semantik und dynamischer Speicherverwaltung.

Chain-Klasse C++ Big Five C++ dynamisches Array C++ Move-Semantik C++ Kopierkonstruktor C++ Destruktor C++ C++ Programmierung lernen STL-freie Implementierung C++ Übungsaufgabe Vektor selbst bauen C++ C++ Speicherverwaltung C++ für Studenten C++ Tutorial Deutsch Chain-Klasse implementieren C++ OOP Grundlagen C++ push_back Methode

Einführung: Warum eine eigene Chain-Klasse schreiben?

In der C++ Programmierung gehört das Verständnis von dynamischen Arrays und der Big Five zu den wichtigsten Grundlagen. Die Aufgabe, eine Chain-Klasse zu implementieren, ist der perfekte Einstieg, um zu verstehen, wie std::vector intern funktioniert – und das ganz ohne STL. Stell dir vor, du entwickelst eine App wie eine To-Do-Liste, bei der Aufgaben dynamisch hinzugefügt werden. Genau das macht eine Chain: Sie wächst und schrumpft mit den Elementen.

Was ist eine Chain?

Eine Chain ist eine dynamische Liste von Elementen – ähnlich wie ein Vektor, aber selbst gebaut. Du speicherst die Elemente in einem dynamischen Array auf dem Heap und verwaltest Größe und Kapazität. Das ist wie bei einem Turnierbaum in der E-Sports-Szene: Die Anzahl der Teilnehmer ändert sich, und du musst Speicher flexibel bereitstellen.

Die Grundstruktur der Chain-Klasse

Wir beginnen mit einer einfachen Klasse, die einen int-Zeiger für das Array, eine Größe (Anzahl der Elemente) und eine Kapazität (aktuell allokierter Speicher) enthält.

class Chain {
private:
    int* array;
    int size;
    int capacity;

public:
    // Konstruktoren
    Chain();
    explicit Chain(int value);
    Chain(const Chain& other);
    Chain(Chain&& other) noexcept;

    // Zuweisungsoperatoren
    Chain& operator=(const Chain& other);
    Chain& operator=(Chain&& other) noexcept;

    // Destruktor
    ~Chain();

    // Weitere Methoden
    void push_back(int value);
    int& operator[](int index);
    int getSize() const;
    void print() const;
};

Die Big Five im Detail

1. Standardkonstruktor

Erzeugt eine leere Chain mit Kapazität 1 (oder 0).

Chain::Chain() : array(new int[1]), size(0), capacity(1) {
    std::cout << "Standardkonstruktor aufgerufen" << std::endl;
}

2. Parameterkonstruktor

Erzeugt eine Chain mit einem Element.

Chain::Chain(int value) : array(new int[1]), size(1), capacity(1) {
    array[0] = value;
    std::cout << "Parameterkonstruktor aufgerufen mit Wert " << value << std::endl;
}

3. Kopierkonstruktor

Erstellt eine tiefe Kopie. Wichtig für die Kopiersemantik.

Chain::Chain(const Chain& other) : array(new int[other.capacity]), size(other.size), capacity(other.capacity) {
    for (int i = 0; i < size; ++i) {
        array[i] = other.array[i];
    }
    std::cout << "Kopierkonstruktor aufgerufen" << std::endl;
}

4. Move-Konstruktor

Übernimmt die Ressourcen einer anderen Chain – effizienter als Kopieren. Das ist wie ein Transferfenster im Fußball: Ein Spieler wechselt den Verein, ohne dass ein neuer Vertrag aufgesetzt werden muss.

Chain::Chain(Chain&& other) noexcept : array(other.array), size(other.size), capacity(other.capacity) {
    other.array = nullptr;
    other.size = 0;
    other.capacity = 0;
    std::cout << "Move-Konstruktor aufgerufen" << std::endl;
}

5. Destruktor

Gibt den Speicher frei.

Chain::~Chain() {
    delete[] array;
    std::cout << "Destruktor aufgerufen" << std::endl;
}

Zuweisungsoperatoren

Kopierzuweisung

Muss selbstzuweisungssicher sein und die Copy-and-Swap-Idiom nutzen.

Chain& Chain::operator=(const Chain& other) {
    if (this != &other) {
        Chain temp(other);
        std::swap(array, temp.array);
        std::swap(size, temp.size);
        std::swap(capacity, temp.capacity);
    }
    std::cout << "Kopierzuweisung aufgerufen" << std::endl;
    return *this;
}

Move-Zuweisung

Übernimmt die Ressourcen einer temporären Chain.

Chain& Chain::operator=(Chain&& other) noexcept {
    if (this != &other) {
        delete[] array;
        array = other.array;
        size = other.size;
        capacity = other.capacity;
        other.array = nullptr;
        other.size = 0;
        other.capacity = 0;
    }
    std::cout << "Move-Zuweisung aufgerufen" << std::endl;
    return *this;
}

Dynamisches Wachstum: push_back

Wenn die Chain voll ist, verdoppeln wir die Kapazität – ähnlich wie std::vector. Das ist wie bei einer Cloud-Speicher-App, die bei Bedarf mehr Speicher bereitstellt.

void Chain::push_back(int value) {
    if (size == capacity) {
        capacity *= 2;
        int* newArray = new int[capacity];
        for (int i = 0; i < size; ++i) {
            newArray[i] = array[i];
        }
        delete[] array;
        array = newArray;
    }
    array[size++] = value;
}

Testen der Chain

Mit cout in den Konstruktoren siehst du, wann die Big Five aufgerufen werden. Ein typischer Test:

Chain a, b, c;
Chain d{10};
std::cout << d[0]; // 10
b.push_back(8);
b.push_back(4);
b.push_back(2);
b.push_back(1);
c = a;
Chain e = b;
Chain f = std::move(c);

Häufige Fehler vermeiden

  • Flache Kopien: Ohne eigenen Kopierkonstruktor teilen sich zwei Chains denselben Speicher – Absturzgefahr.
  • Speicherlecks: Vergiss nicht, im Destruktor delete[] aufzurufen.
  • Selbstzuweisung: a = a darf nicht crashen.

Ausblick: Chain für andere Datentypen

Mit Templates kannst du die Chain für beliebige Typen nutzen – wie std::vector<T>. Das ist der nächste Schritt für fortgeschrittene C++-Programmierung.

Fazit

Das Erstellen einer eigenen Chain-Klasse ist eine hervorragende Übung, um die dynamische Speicherverwaltung und die Big Five in C++ zu meistern. Mit diesem Wissen bist du bestens gerüstet für komplexe Projekte – sei es in der Spieleentwicklung, bei KI-Anwendungen oder in der Finanzsoftware. Viel Erfolg beim Programmieren!