Storia della questione:
I puntatori normali (raw) sono il meccanismo tradizionale in C++ per lavorare con la memoria dinamica. Questo è un meccanismo astratto universale, ma sfortunatamente è molto soggetto a errori: perdite di memoria, doppie eliminazioni, errori di Dangling pointer. Perciò, a partire da C++11, la libreria standard include puntatori intelligenti — classi template (std::unique_ptr, std::shared_ptr, std::weak_ptr) che gestiscono automaticamente il tempo di vita dell'oggetto.
Problema:
Quando si utilizzano puntatori normali, la responsabilità per l'allocazione e la liberazione della memoria ricade sul programmatore. Errori nella liberazione della memoria portano a perdite di memoria (memory leaks), corruzione dei dati, crash del programma. Casi particolarmente complessi si verificano nella gestione delle eccezioni o quando i puntatori vengono passati ad altre funzioni.
Soluzione:
I puntatori intelligenti incapsulano la memoria allocata e la liberano automaticamente quando non ci sono più proprietari. Implementano RAII. std::unique_ptr fornisce un possesso esclusivo, std::shared_ptr — possesso condiviso, std::weak_ptr — non controllante (per prevenire "cicli di riferimento").
Esempio di codice:
#include <memory> void foo() { std::unique_ptr<int> p = std::make_unique<int>(5); // la memoria verrà liberata anche in caso di eccezione // ... }
Caratteristiche chiave:
Si può usare std::unique_ptr su un array creato tramite new[]?
No, per gli array usa std::unique_ptr<T[]>: in questo modo verrà chiamato delete[] invece di delete.
std::unique_ptr<int[]> arr(new int[10]);
I puntatori intelligenti standard possono prevenire tutte le possibili perdite di memoria?
No. Ad esempio, i riferimenti ciclici tra std::shared_ptr porteranno a perdite. Per rompere tali cicli si usa std::weak_ptr.
Possono i puntatori intelligenti "eliminare" lo stesso oggetto due volte?
No, a meno che non si violi la logica di possesso (non usare puntatori normali!). Se si copia manualmente un puntatore normale, allora la distruzione potrebbe avvenire due volte.
Si usano puntatori normali, la memoria viene liberata manualmente, in caso di eccezione la memoria non viene liberata.
Pro:
Contro:
Si usano std::unique_ptr e std::make_unique per creare oggetti e passarli a funzioni.
Pro:
Contro: