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 Operationen wie vec[0] = createBuffer(); viel effizienter werden.

challenge icon

Aufgabe

Einfach

Lassen Sie uns eine DynamicString-Klasse erstellen, die ein dynamisch zugewiesenes Zeichenarray verwaltet und Zuweisungen zwischen bestehenden Objekten ordnungsgemäß handhabt. Dies ist ein praktisches Szenario, in dem Sie String-Daten sicher von einem Objekt auf ein anderes übertragen müssen, ohne Speicherlecks oder hängende Zeiger zu verursachen.

Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:

  • DynamicString.h: Definieren Sie eine DynamicString-Klasse, die einen C-String unter Verwendung von dynamischem Speicher speichert. Ihre Klasse sollte Folgendes verwalten:
    • Einen privaten char*-Zeiger für die String-Daten
    • Ein privates size_t für die Länge
    • Einen Konstruktor, der ein const char* entgegennimmt und eine tiefe Kopie erstellt
    • Einen Destruktor, der den zugewiesenen 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 den internen String zurückgibt (const)
    • Eine length()-Methode, die die String-Länge zurückgibt (const)

    Ihr Kopierzuweisungsoperator muss die vier wesentlichen Schritte befolgen: Prüfung auf Selbstzuweisung, Bereinigung vorhandener Ressourcen, Kopieren der neuen Daten und Rückgabe von *this. Der Verschiebezuweisungsoperator sollte den Zeiger der Quelle übernehmen und die Quelle in einem gültigen leeren Zustand hinterlassen (nullptr mit Länge 0).

  • main.cpp: Lesen Sie drei Strings von der Eingabe ein (jeder in einer separaten Zeile). Erstellen Sie drei DynamicString-Objekte: str1 mit der ersten Eingabe, str2 mit der zweiten Eingabe und str3 mit der dritten Eingabe.

    Demonstrieren Sie Ihre Zuweisungsoperatoren:

    1. Geben Sie den Anfangszustand aller drei Strings aus
    2. Verwenden Sie die Kopierzuweisung: str1 = str2;
    3. Geben Sie str1 und str2 nach der Kopierzuweisung aus (beide sollten den gleichen Inhalt haben)
    4. Verwenden Sie die Verschiebezuweisung: str2 = std::move(str3);
    5. Geben Sie str2 nach der Verschiebezuweisung und die Länge von str3 aus (sollte 0 sein, nachdem sie verschoben wurde)

    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

Verwenden Sie <cstring> für strlen und strcpy. Markieren Sie Ihren Verschiebezuweisungsoperator als noexcept. Binden Sie <utility> in main.cpp für std::move ein. Vergessen Sie nicht die Header-Guards in Ihrer Header-Datei.

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