Menu
Coddy logo textTech

Sovraccarico dell'operatore di assegnazione

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 44 di 104.

L’operatore di assegnazione per copia (=) viene chiamato quando assegni un oggetto esistente a un altro. A differenza del costruttore di copia (che crea un nuovo oggetto), l’operatore di assegnazione lavora con un oggetto che esiste già e potrebbe avere risorse da liberare prima.

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. Self-assignment check
            delete[] data;                  // 2. Clean up existing resource
            size = other.size;              // 3. Copy the data
            data = new int[size];
            for (size_t i = 0; i < size; ++i)
                data[i] = other.data[i];
        }
        return *this;                       // 4. Return *this
    }
};

Il controllo di autoassegnazione (this != &other) è fondamentale. Senza di esso, b = b; eliminerebbe i dati prima di provare a copiarli, causando un comportamento indefinito.

L'operatore restituisce *this per riferimento, consentendo concatenazioni come a = b = c;. Questo corrisponde al comportamento dei tipi integrati.

Per le classi che gestiscono risorse, spesso implementerai sia gli operatori di assegnazione per copia sia quelli di assegnazione per spostamento:

Buffer& operator=(Buffer&& other) noexcept {
    if (this != &other) {
        delete[] data;           // Libera la risorsa corrente
        data = other.data;       // Acquisisci la risorsa
        size = other.size;
        other.data = nullptr;    // Lascia l'oggetto sorgente in uno stato valido
        other.size = 0;
    }
    return *this;
}

L'operatore di assegnazione per spostamento trasferisce la proprietà invece di copiare, rendendo operazioni come vec[0] = createBuffer(); molto più efficienti.

challenge icon

Sfida

Facile

Creiamo una classe DynamicString che gestisce un array di caratteri allocato dinamicamente e gestisce correttamente l'assegnazione tra oggetti esistenti. Questo è uno scenario pratico in cui devi trasferire in modo sicuro i dati di una stringa da un oggetto a un altro senza perdite di memoria o puntatori pendenti.

Creerai due file per organizzare il codice:

  • DynamicString.h: definisci una classe DynamicString che memorizza una stringa in stile C usando memoria dinamica. La tua classe deve gestire:
    • Un puntatore privato char* per i dati della stringa
    • Un size_t privato per la lunghezza
    • Un costruttore che accetta un const char* e crea una copia profonda
    • Un distruttore che libera correttamente la memoria allocata
    • Un operatore di assegnazione per copia che esegue una copia profonda proteggendosi dall'autoassegnazione
    • Un operatore di assegnazione per spostamento che trasferisce la proprietà in modo efficiente
    • Un metodo c_str() che restituisce la stringa interna (const)
    • Un metodo length() che restituisce la lunghezza della stringa (const)

    L'operatore di assegnazione per copia deve seguire i quattro passaggi essenziali: verificare l'autoassegnazione, liberare le risorse esistenti, copiare i nuovi dati e restituire *this. L'operatore di assegnazione per spostamento deve sottrarre il puntatore alla sorgente e lasciare la sorgente in uno stato vuoto valido (nullptr con lunghezza 0).

  • main.cpp: leggi tre stringhe dall'input (ciascuna su una riga separata). Crea tre oggetti DynamicString: str1 con il primo input, str2 con il secondo input e str3 con il terzo input.

    Mostra il funzionamento degli operatori di assegnazione:

    1. Stampa lo stato iniziale di tutte e tre le stringhe
    2. Usa l'assegnazione per copia: str1 = str2;
    3. Stampa str1 e str2 dopo l'assegnazione per copia (entrambi devono avere lo stesso contenuto)
    4. Usa l'assegnazione per spostamento: str2 = std::move(str3);
    5. Stampa str2 dopo l'assegnazione per spostamento e la lunghezza di str3 (deve essere 0 dopo lo spostamento)

    Formato dell'output:

    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

Usa <cstring> per strlen e strcpy. Contrassegna l'operatore di assegnazione per spostamento come noexcept. Includi <utility> in main.cpp per std::move. Non dimenticare le protezioni dell'header nel file header.

Provalo tu

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

using namespace std;

int main() {
    // Leggi tre stringhe dall'input
    string input1, input2, input3;
    getline(cin, input1);
    getline(cin, input2);
    getline(cin, input3);

    // Crea tre oggetti DynamicString
    DynamicString str1(input1.c_str());
    DynamicString str2(input2.c_str());
    DynamicString str3(input3.c_str());

    // TODO: Stampa lo stato iniziale di tutte e tre le stringhe
    // Formato:
    // Initial:
    // str1: <value>
    // str2: <value>
    // str3: <value>

    // TODO: Usa l'assegnazione per copia: str1 = str2;

    // TODO: Stampa str1 e str2 dopo l'assegnazione per copia
    // Formato:
    // After copy (str1 = str2):
    // str1: <value>
    // str2: <value>

    // TODO: Usa l'assegnazione per spostamento: str2 = std::move(str3);

    // TODO: Stampa str2 dopo lo spostamento e la lunghezza di str3
    // Formato:
    // After move (str2 = std::move(str3)):
    // str2: <value>
    // str3 length: 0

    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C++ online