ProgrammazioneSviluppatore C++

Quali sono le differenze tra shallow copy e deep copy in C++? In quali situazioni è opportuno implementare manualmente la copia profonda e come farlo correttamente?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Shallow copy (copia superficiale) – copia solo i valori dei campi dell'oggetto, inclusi i puntatori, ma non duplica la memoria allocata dinamicamente. Di conseguenza, entrambi gli oggetti puntano alla stessa area di memoria. Questo può portare a errori durante la modifica dei dati o il rilascio della memoria.

Deep copy (copia profonda) – crea una copia completa di tutte le risorse a cui fa riferimento l'oggetto, in modo che ciascun oggetto possieda la propria copia dei dati.

Quando è necessaria la deep copy:

  • Quando l'oggetto possiede memoria allocata dinamicamente.
  • Quando la modifica del contenuto di un oggetto non dovrebbe influenzare l'altro.

Esempio di implementazione di deep copy:

class ArrayHolder { public: ArrayHolder(size_t size) : sz(size), data(new int[size]) {} ~ArrayHolder() { delete[] data; } // Costruttore di copia profonda ArrayHolder(const ArrayHolder& other) : sz(other.sz), data(new int[other.sz]) { std::copy(other.data, other.data + other.sz, data); } // Assegnazione di copia profonda ArrayHolder& operator=(const ArrayHolder& other) { if (this != &other) { delete[] data; sz = other.sz; data = new int[sz]; std::copy(other.data, other.data + sz, data); } return *this; } private: size_t sz; int* data; };

Domanda insidiosa.

Domanda: Funzionerà correttamente il costruttore di copia se in esso viene semplicemente copiato il valore del puntatore?

Risposta: No, questo porterà a una doppia eliminazione della memoria quando entrambi gli oggetti vengono distrutti. È necessario implementare la copia profonda per una corretta gestione delle risorse.

Esempi di errori reali causati dalla mancanza di conoscenza delle sfumature dell'argomento.


Storia

In uno dei progetti, per trasferire array tra i moduli, venivano utilizzati oggetti di una classe in cui il costruttore di copia predefinito copiava solo il puntatore (shallow copy). Di conseguenza, dopo l'uscita di un oggetto temporaneo dal contesto, l'array veniva distrutto, mentre l'oggetto principale rimaneva con un puntatore "appeso", portando a comportamenti indefiniti e crash dell'applicazione.


Storia

In una libreria per lavorare con le immagini, venivano ripetutamente copiati oggetti contenenti buffer allocati dinamicamente. A causa dell'assenza di deep copy, dopo il rilascio della memoria in un oggetto, un altro accedeva all'area liberata. Si manifestavano sia danni ai dati che crash durante l'eliminazione dell'oggetto.


Storia

Durante l'integrazione di codice obsoleto con standard moderni, nelle vecchie classi non erano stati implementati né il costruttore di copia né l'operatore di assegnazione. L'uso di queste classi con contenitori della libreria standard portava a inattesi crash, poiché i contenitori copiavano gli oggetti superficialmente.