Il mondo in cui vive Bjarne è molto ... accademico, per mancanza di un termine migliore. Se il tuo codice può essere progettato e strutturato in modo tale che gli oggetti abbiano gerarchie relazionali molto deliberate, in modo tale che le relazioni di proprietà siano rigide e inflessibili, il codice scorre in una direzione (da livello alto a livello basso) e gli oggetti parlano solo a quelli inferiori la gerarchia, quindi non troverai molto bisogno shared_ptr
. È qualcosa che usi in quelle rare occasioni in cui qualcuno deve infrangere le regole. Altrimenti, puoi semplicemente inserire tutto in vector
s o altre strutture di dati che usano la semantica di valore e unique_ptr
s per cose che devi allocare singolarmente.
Anche se è un mondo fantastico in cui vivere, non è quello che devi fare tutto il tempo. Se non riesci a organizzare il tuo codice in quel modo, perché la progettazione del sistema che stai cercando di realizzare significa che è impossibile (o semplicemente profondamente spiacevole), allora ti ritroverai sempre più a dover condividere la proprietà degli oggetti .
In un tale sistema, tenere puntatori nudi non è ... esattamente pericoloso, ma solleva domande. La cosa grandiosa shared_ptr
è che fornisce ragionevoli garanzie sintattiche sulla durata dell'oggetto. Può essere rotto? Ovviamente. Ma le persone possono anche const_cast
cose; le cure di base e l'alimentazione shared_ptr
dovrebbero fornire una ragionevole qualità di vita per gli oggetti assegnati i cui proprietari devono essere condivisi.
Quindi, ci sono weak_ptr
s, che non possono essere usati in assenza di a shared_ptr
. Se il tuo sistema è rigidamente strutturato, puoi archiviare un puntatore nudo su un oggetto, con la certezza che la struttura dell'applicazione garantisce che l'oggetto puntato ti sopravviverà. È possibile chiamare una funzione che restituisce un puntatore a un valore interno o esterno (ad esempio trova un oggetto chiamato X). Nel codice adeguatamente strutturato, tale funzione sarebbe disponibile solo se la durata dell'oggetto fosse garantita superiore a quella dell'utente; quindi, archiviare quel puntatore nudo nel tuo oggetto va bene.
Dal momento che quella rigidità non è sempre possibile raggiungere nei sistemi reali, è necessario un modo per garantire ragionevolmente la durata. A volte, non è necessaria la piena proprietà; a volte, devi solo essere in grado di sapere quando il puntatore è cattivo o buono. Ecco dove weak_ptr
entra in gioco. Ci sono stati casi in cui avrei potuto usare un unique_ptr
o boost::scoped_ptr
, ma ho dovuto usare un shared_ptr
perché avevo specificamente bisogno di dare a qualcuno un puntatore "volatile". Un puntatore la cui durata era indeterminata e potevano interrogare quando quel puntatore veniva distrutto.
Un modo sicuro per sopravvivere quando lo stato del mondo è indeterminato.
Potrebbe essere stato fatto da qualche chiamata di funzione per ottenere il puntatore, anziché tramite weak_ptr
? Sì, ma potrebbe essere più facilmente risolto. Una funzione che restituisce un puntatore nudo non ha modo di suggerire sintatticamente che l'utente non faccia qualcosa come archiviare quel puntatore a lungo termine. Restituire a shared_ptr
rende anche troppo facile per qualcuno semplicemente memorizzarlo e potenzialmente prolungare la durata di vita di un oggetto. Restituire un weak_ptr
comunque suggerisce fortemente che la memorizzazione di ciò shared_ptr
che ottieni lock
è un'idea ... dubbia. Non ti impedirà di farlo, ma nulla in C ++ ti impedisce di violare il codice. weak_ptr
fornisce una resistenza minima dal fare la cosa naturale.
Ora, questo non vuol dire che shared_ptr
non può essere abusato ; certamente può. Soprattutto pre unique_ptr
, ci sono stati molti casi in cui ho appena usato un boost::shared_ptr
perché avevo bisogno di passare un puntatore RAII o inserirlo in un elenco. Senza mossa semantica e unique_ptr
, boost::shared_ptr
era l'unica vera soluzione.
E puoi usarlo in luoghi in cui è del tutto superfluo. Come detto sopra, un'adeguata struttura del codice può eliminare la necessità di alcuni usi di shared_ptr
. Ma se il tuo sistema non può essere strutturato come tale e continua a fare ciò di cui ha bisogno, shared_ptr
sarà di grande utilità.