ProgrammazioneSviluppatore C++ Backend

Descrivi i meccanismi di controllo della memoria in C++. Qual è la differenza tra new/delete e smart pointers, e perché è preferibile utilizzare puntatori intelligenti?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

In C++, la gestione della memoria avviene tramite gli operatori espliciti new e delete, che allocano e liberano memoria dinamicamente. Tuttavia, con la gestione manuale è facile incorrere in perdite di memoria o in una doppia eliminazione.

Con l'introduzione dello standard C++11 sono stati introdotti i puntatori intelligenti — come std::unique_ptr, std::shared_ptr, std::weak_ptr. Essi gestiscono automaticamente il ciclo di vita degli oggetti e garantiscono il rilascio delle risorse al termine della loro visibilità, anche in caso di eccezioni.

Esempio di confronto:

// Rilascio manuale della memoria Foo* ptr = new Foo(); // ... delete ptr; // Più sicuro con un puntatore intelligente std::unique_ptr<Foo> ptr2 = std::make_unique<Foo>(); // delete non è richiesto — tutto sarà gestito da unique_ptr

I puntatori intelligenti riducono il rischio di perdite di memoria e rendono il codice più sicuro e leggibile.

Domanda insidiosa.

Cosa succede se si chiama delete due volte per lo stesso puntatore?

Risposta: Dopo la prima chiamata a delete, la memoria è già stata liberata. Una chiamata successiva porterà a un comportamento indefinito (undefined behavior). Esempio:

Foo* p = new Foo(); delete p; delete p; // ERRORE!

Per evitare ciò, imposta il puntatore su nullptr dopo il rilascio:

delete p; p = nullptr;

Esempi di errori reali a causa della mancanza di conoscenza dei dettagli di questo argomento.


Storia

In un grande progetto C++, uno sviluppatore liberava manualmente la memoria dinamica tramite delete, dimenticando di azzerare il puntatore uscendo da diversi rami della funzione in caso di eccezioni. Questo ha portato a perdite di memoria, rilevate solo durante il testing di carico.


Storia

Cercando di condividere puntatori raw tra diverse parti del codice, è sorto un doppio rilascio della memoria — alcune parti del codice facevano delete, senza avvisare le altre. Risultato: segfault in produzione, l'analisi del core dump ha mostrato subito la causa.


Storia

Dopo la migrazione di un vecchio progetto ai nuovi standard C++, è stata lasciata una parte di codice con puntatori raw, mentre le nuove classi operavano già con puntatori intelligenti. Si sono incontrati errori di trasferimento della proprietà delle risorse: la memoria veniva liberata "due volte" — prima manualmente e poi automaticamente dai distruttori dei puntatori intelligenti.