ProgrammazioneSviluppatore C++

Spiega la differenza tra shallow copy e deep copy con un esempio di un contenitore con memoria dinamica. Come implementare correttamente la copia profonda?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Lo shallow copy (copia superficiale) copia solo i valori dei membri della classe, inclusi i puntatori, ma non copia i dati a cui questi puntatori puntano. La deep copy (copia profonda) crea nuove copie dei dati che si trovano ai puntatori, evitando la condivisione della memoria e il doppio rilascio della memoria.

Esempio:

class Buffer { public: Buffer(size_t size) : size(size), data(new int[size]) {} // Shallow copy (errato) Buffer(const Buffer& other) : size(other.size), data(other.data) {} // Deep copy (corretto) Buffer& operator=(const Buffer& other) { if (this != &other) { delete[] data; size = other.size; data = new int[size]; std::copy(other.data, other.data + size, data); } return *this; } ~Buffer() { delete[] data; } private: size_t size; int* data; };

Domanda insidiosa.

Se la classe contiene un puntatore a un array dinamico, perché non è sufficiente copiare e incollare il costruttore di copia e l'operatore= predefiniti?

Risposta corretta:

La copia predefinita implementa una copia superficiale. Due oggetti punteranno allo stesso array, e durante la distruzione ci sarà un tentativo di liberare due volte la stessa memoria (double free), il che porterà a un crash.

Esempi di errori reali causati dalla mancanza di comprensione delle complessità dell'argomento.


Storia In una grande applicazione server è stata implementata una classe Image personalizzata che gestiva un buffer dinamico di pixel. Gli sviluppatori non hanno implementato la copia profonda, e durante il passaggio di oggetti Image per valore tra i thread si verificava un doppio rilascio della memoria, portando a crash ogni pochi giorni.


Storia In un progetto studentesco è stato utilizzato un contenitore Field, contenente un puntatore a un array di celle allocato dinamicamente. Quando la dimensione dell'array è stata modificata, il costruttore di copia copiava solo il puntatore, e entrambi i contenitori operavano sulla stessa area di memoria, portando a dati inconsistenti e bug difficili da trovare.


Storia Nel vecchio codice C++ di un motore grafico è stata implementata una classe Texture senza il proprio distruttore e operatore di assegnazione, il che ha portato a memory leak — perdite di memoria durante la copia e l'assegnazione di oggetti temporanei delle texture.