Staccare un puntatore da uno shared_ptr? [duplicare]
-
11-09-2019 - |
Domanda
Eventuali duplicati:
Come liberare puntatore da boost :: shared_ptr?
Una funzione di mia interfaccia restituisce un puntatore ad un oggetto. L'utente dovrebbe assumere la proprietà di tale oggetto. Non voglio tornare un Boost.shared_ptr, perché non voglio forzare i clienti a utilizzare boost. Internamente però, vorrei memorizzare il puntatore in una shared_ptr per evitare perdite di memoria in caso di eccezioni, ecc Non sembra esserci alcun modo per staccare un puntatore da un puntatore condiviso. Tutte le idee qui?
Soluzione
Quello che stai cercando è una funzione release
; shared_ptr
non dispone di una funzione di rilascio. Per il manuale di Boost :
Q. Perché non shared_ptr fornire una funzione di rilascio ()?
A. shared_ptr non può dare via proprietà meno che non sia unico (), perché l'altra copia sarà ancora distruggere l'oggetto.
Si consideri:
shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2
int * p = a.release();
// Who owns p now? b will still call delete on it in its destructor.
Inoltre, il puntatore restituito da release () sarebbe difficile da rilasciare in modo affidabile, come lo shared_ptr fonte potrebbe essere stato creato con un deleter personalizzato.
Due opzioni che si potrebbe prendere in considerazione:
- Si potrebbe utilizzare
std::tr1::shared_ptr
, che richiederebbe agli utenti di utilizzare un'implementazione C ++ librerie di supporto TR1 o per utilizzare Boost; almeno questo darebbe loro la possibilità di scegliere tra i due. - Si potrebbe implementare il proprio puntatore condiviso
boost::shared_ptr
-like e l'uso che sulle interfacce esterne.
Si potrebbe anche guardare la discussione a questa domanda sulla usando boost :: shared_ptr nell'interfaccia di una biblioteca pubblica.
Altri suggerimenti
c'è sempre un modo: -)
V'è infatti una ragione per cui essi non forniscono un metodo di rilascio (), ma non è impossibile crearne uno. Fai la tua deleter. Qualcosa sulla linea del (non hanno effettivamente compilato il codice, ma questa è la nozione generale):
template <typename T>
class release_deleter{
public:
release_deleter() : released_(new some_atomic_bool(false)){}
void release() {released_->set(true);}
void operator()(T* ptr){if(!released_->get()) delete ptr;}
private:
shared_ptr<some_atomic_bool> released_;
}
..
shared_ptr<some_type> ptr(new some_type, release_deleter<some_type>());
..
release_deleter<some_type>* deleter = get_deleter<release_deleter<some_type>>(ptr);
deleter->release();
some_type* released_ptr = ptr.get();
L'utente dovrebbe assumere la proprietà di tale oggetto. Non voglio tornare un Boost.shared_ptr,
shared_ptr
esprime condiviso di proprietà, e si desidera l'interfaccia per esprimere trasferimento di proprietà. std::auto_ptr
sarebbe quindi più applicabili qui.
Internamente però, vorrei memorizzare il puntatore in una shared_ptr per evitare perdite di memoria in caso di eccezioni
Anche in questo caso, shared_ptr
non può essere lo strumento migliore per quel lavoro. Per evitare perdite nel caso di eccezioni, scoped_ptr
o auto_ptr
sarebbero più adatti.
Utilizzare un shared_ptr
ad un scoped_ptr
alla risorsa (shared_ptr<scoped_ptr<Resource>>
). In questo modo si ottiene il conteggio dei riferimenti di shared_ptr
, che distruggerà automaticamente la risorsa se e solo se è ancora attaccato alla scoped_ptr
. Ma si può staccare la scoped_ptr
quando si è a portata di mano fuori della proprietà.
Come James è ben coperto non si può davvero staccare un puntatore condiviso.
Hai bisogno di più proprietari internamente, o stai trasferendo la proprietà dalla classe al cliente? In quel caso un std::auto_ptr
potrebbe misura la fattura.
Se siete preoccupati per la semantica sorprendenti std::auto_ptr
, si potrebbe tenere internamente da boost::scoped_ptr
, e staccarlo in corrispondenza del punto di consegnare fuori - lasciando al cliente di eliminare manualmente o riporlo nel proprio puntatore intelligente.
Se si dispone di più proprietari dalla vostra parte si potrebbe usare un conteggio invadente. Internamente si potrebbe quindi utilizzare boost::intrusive__ptr
, ma mano fuori il puntatore grezzo a livello di interfaccia. Il client può quindi lavorare manualmente con i conteggi ref, o conservarla in un boost::intrusive_ptr
se stessi (ma non farli dipendono da esso)