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.
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;
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.