Menu
Coddy logo textTech

Zuweisungsoperatorüberladung

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 44 von 104.

Der Kopierzuweisungsoperator (=) wird aufgerufen, wenn Sie ein bestehendes Objekt einem anderen zuweisen. Im Gegensatz zum Kopierkonstruktor (der ein neues Objekt erstellt), arbeitet der Zuweisungsoperator mit einem Objekt, das bereits existiert und möglicherweise über Ressourcen verfügt, die zuerst bereinigt werden müssen.

class Buffer {
    int* data;
    size_t size;
    
public:
    Buffer(size_t s) : size(s), data(new int[s]) {}
    ~Buffer() { delete[] data; }
    
    Buffer& operator=(const Buffer& other) {
        if (this != &other) {              // 1. Prüfung auf Selbstzuweisung
            delete[] data;                  // 2. Bestehende Ressource bereinigen
            size = other.size;              // 3. Daten kopieren
            data = new int[size];
            for (size_t i = 0; i < size; ++i)
                data[i] = other.data[i];
        }
        return *this;                       // 4. *this zurückgeben
    }
};

Die Selbstzuweisungsprüfung (this != &other) ist entscheidend. Ohne sie würde b = b; die Daten löschen, bevor versucht wird, sie zu kopieren, was zu undefiniertem Verhalten führt.

Der Operator gibt *this per Referenz zurück, um Verkettungen wie a = b = c; zu ermöglichen. Dies entspricht dem Verhalten eingebauter Typen.

Für Klassen, die Ressourcen verwalten, werden Sie oft sowohl Kopier- als auch Verschiebe-Zuweisungsoperatoren implementieren:

Buffer& operator=(Buffer&& other) noexcept {
    if (this != &other) {
        delete[] data;           // Aktuelle Ressource bereinigen
        data = other.data;       // Ressource übernehmen
        size = other.size;
        other.data = nullptr;    // Quelle in gültigem Zustand hinterlassen
        other.size = 0;
    }
    return *this;
}

Der Move-Zuweisungsoperator überträgt den Besitz, anstatt zu kopieren, wodurch Vorgänge wie vec[0] = createBuffer(); deutlich effizienter werden.

challenge icon

Aufgabe

Einfach

Lass uns eine DynamicString-Klasse erstellen, die ein dynamisch allokiertes Zeichenarray verwaltet und die Zuweisung zwischen bereits vorhandenen Objekten ordnungsgemäß behandelt. Dies ist ein praxisnahes Szenario, in dem du Zeichenkettendaten sicher von einem Objekt auf ein anderes übertragen musst, ohne Speicherlecks oder hängende Zeiger zu verursachen.

Du erstellst zwei Dateien, um deinen Code zu organisieren:

  • DynamicString.h: Definiere eine DynamicString-Klasse, die eine Zeichenkette im C-Stil mithilfe von dynamischem Speicher speichert. Deine Klasse sollte Folgendes verwalten:
    • Einen privaten char*-Zeiger für die Zeichkettendaten
    • Eine private size_t-Variable für die Länge
    • Einen Konstruktor, der einen const char* übernimmt und eine tiefe Kopie erstellt
    • Einen Destruktor, der den allokierten Speicher ordnungsgemäß freigibt
    • Einen Kopierzuweisungsoperator, der eine tiefe Kopie mit Schutz vor Selbstzuweisung durchführt
    • Einen Verschiebezuweisungsoperator, der den Besitz effizient überträgt
    • Eine c_str()-Methode, die die interne Zeichenkette zurückgibt (const)
    • Eine length()-Methode, die die Länge der Zeichenkette zurückgibt (const)

    Dein Kopierzuweisungsoperator muss die vier wesentlichen Schritte befolgen: Selbstzuweisung prüfen, vorhandene Ressourcen freigeben, die neuen Daten kopieren und *this zurückgeben. Der Verschiebezuweisungsoperator sollte den Zeiger der Quelle übernehmen und die Quelle in einem gültigen leeren Zustand belassen (nullptr mit der Länge 0).

  • main.cpp: Lies drei Zeichenketten aus der Eingabe ein (jeweils in einer eigenen Zeile). Erstelle drei DynamicString-Objekte: str1 mit der ersten Eingabe, str2 mit der zweiten Eingabe und str3 mit der dritten Eingabe.

    Demonstriere deine Zuweisungsoperatoren:

    1. Gib den Anfangszustand aller drei Zeichenketten aus
    2. Verwende die Kopierzuweisung: str1 = str2;
    3. Gib str1 und str2 nach der Kopierzuweisung aus (beide sollten denselben Inhalt haben)
    4. Verwende die Verschiebezuweisung: str2 = std::move(str3);
    5. Gib str2 nach der Verschiebezuweisung und die Länge von str3 aus (sie sollte nach dem Verschieben 0 sein)

    Ausgabeformat:

    Initial:
    str1: <value>
    str2: <value>
    str3: <value>
    After copy (str1 = str2):
    str1: <value>
    str2: <value>
    After move (str2 = std::move(str3)):
    str2: <value>
    str3 length: 0

Verwende <cstring> für strlen und strcpy. Kennzeichne deinen Verschiebezuweisungsoperator mit noexcept. Binde <utility> in main.cpp für std::move ein. Vergiss die Header-Guards in deiner Header-Datei nicht.

Probier es selbst

#include <iostream>
#include <string>
#include <utility>
#include "DynamicString.h"

using namespace std;

int main() {
    // Drei Strings von der Eingabe lesen
    string input1, input2, input3;
    getline(cin, input1);
    getline(cin, input2);
    getline(cin, input3);

    // Drei DynamicString-Objekte erstellen
    DynamicString str1(input1.c_str());
    DynamicString str2(input2.c_str());
    DynamicString str3(input3.c_str());

    // TODO: Initialzustand aller drei Strings ausgeben
    // Format:
    // Initial:
    // str1: <value>
    // str2: <value>
    // str3: <value>

    // TODO: Kopierzuweisung verwenden: str1 = str2;

    // TODO: str1 und str2 nach der Kopierzuweisung ausgeben
    // Format:
    // After copy (str1 = str2):
    // str1: <value>
    // str2: <value>

    // TODO: Verschiebezuweisung verwenden: str2 = std::move(str3);

    // TODO: str2 nach dem Verschieben und die Länge von str3 ausgeben
    // Format:
    // After move (str2 = std::move(str3)):
    // str2: <value>
    // str3 length: 0

    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C++-Compiler