Quando useresti uno std :: auto_ptr invece di boost :: shared_ptr?
-
22-07-2019 - |
Domanda
Siamo praticamente passati all'utilizzo di boost :: shared_ptr
in tutto il nostro codice, tuttavia abbiamo ancora alcuni casi isolati in cui utilizziamo std :: auto_ptr
, comprese le classi singleton:
template < typename TYPE >
class SharedSingleton
{
public:
static TYPE& Instance()
{
if (_ptrInstance.get() == NULL)
_ptrInstance.reset(new TYPE);
return *_ptrInstance;
}
protected:
SharedSingleton() {};
private:
static std::auto_ptr < TYPE > _ptrInstance;
};
Mi è stato detto che c'è un'ottima ragione per cui questo non è stato creato un shared_ptr
, ma per la mia vita non riesco a capire perché? So che auto_ptr
alla fine verrà contrassegnato come ammortizzato nel prossimo standard, quindi vorrei sapere cosa / come posso sostituire questa implementazione .
Inoltre, ci sono altri motivi per cui potresti prendere in considerazione l'uso di un auto_ptr
invece di un shared_ptr
? e vedi qualche problema trasferirsi in shared_ptr in futuro?
Modifica:
- Quindi, in risposta a " posso tranquillamente sostituire
auto_ptr
conshared_ptr
nel codice sopra " ;, la risposta è sì - comunque prenderò un piccolo risultato . - Quando
auto_ptr
viene infine contrassegnato come ammortizzato e passiamo astd :: shared_ptr
, avremo bisogno di testare accuratamente il nostro codice per assicurarci di rispettare dalla diversa semantica della proprietà.
Soluzione
auto_ptr
e shared_ptr
risolvono problemi completamente diversi. Uno non sostituisce l'altro.
auto_ptr
è un sottile wrapper attorno ai puntatori per implementare RAII semantica , in modo che le risorse vengano sempre rilasciate, anche di fronte a eccezioni. auto_ptr
non esegue alcun conteggio dei riferimenti o simili, non fa in modo che più puntatori puntino allo stesso oggetto durante la creazione di copie. In effetti, è molto diverso. auto_ptr
è una delle poche classi in cui l'operatore di assegnazione modifica l'oggetto sorgente . Considera questa spina spudorata dalla pagina wikipedia auto_ptr :
int *i = new int;
auto_ptr<int> x(i);
auto_ptr<int> y;
y = x;
cout << x.get() << endl; // Print NULL
cout << y.get() << endl; // Print non-NULL address i
Nota come eseguire
y = x;
modifica non solo y ma anche x.
Il modello boost :: shared_ptr
semplifica la gestione di più puntatori allo stesso oggetto e l'oggetto viene eliminato solo dopo che l'ultimo riferimento è uscito dall'ambito. Questa funzione non è utile nel tuo scenario, che (tenta di) implementare un Singleton . Nel tuo scenario, ci sono sempre 0 riferimenti a 1 riferimento all'unico oggetto della classe, se presente.
In sostanza, gli oggetti auto_ptr
e gli oggetti shared_ptr
hanno una semantica completamente diversa (ecco perché non puoi usare il primo in contenitori, ma farlo con il secondo va bene), e spero che abbiate buoni test per rilevare eventuali regressioni introdotte durante il porting del codice. : -}
Altri suggerimenti
Altri hanno risposto perché questo codice utilizza un auto_ptr
anziché un shared_ptr
. Per rispondere ad altre tue domande:
Cosa / come posso sostituire questa implementazione?
Usa boost :: scoped_ptr
o unique_ptr
(disponibile sia in Boost che nel nuovo standard C ++). Sia scoped_ptr
che unique_ptr
forniscono una proprietà rigorosa (e nessun sovraccarico di conteggio dei riferimenti) ed evitano la sorprendente semantica di eliminazione su copia di auto_ptr
.
Inoltre, ci sono altri motivi per cui potresti prendere in considerazione l'uso di un auto_ptr
invece di un shared_ptr
? E riscontri problemi nel passaggio a shared_ptr
in futuro?
Personalmente, non userei un auto_ptr
. Delete-on-copy è troppo intuitivo. Herb Sutter sembra essere d'accordo . Passare a scoped_ptr
, unique_ptr
o shared_ptr
non dovrebbe offrire problemi. In particolare, shared_ptr
dovrebbe essere una sostituzione drop-in se non ti interessa l'overhead del conteggio dei riferimenti. scoped_ptr
è un sostituto drop-in se non si utilizzano le funzionalità di trasferimento della proprietà di auto_ptr
. Se si utilizza il trasferimento di proprietà, unique_ptr
è quasi una sostituzione drop-in, tranne per il fatto che è necessario chiamare esplicitamente move
per trasferire la proprietà. Vedi qui per un esempio.
auto_ptr è l'unico tipo di puntatore intelligente che uso. Lo uso perché non uso Boost e perché in genere preferisco esplicitamente le mie classi orientate al business / alle applicazioni definire la semantica e l'ordine di cancellazione, piuttosto che dipendere da raccolte di, o singoli, puntatori intelligenti.