Per cosa viene utilizzato boost's shared_ptr (shared_ptr < Y > const & amp; r, T * p)?
-
05-07-2019 - |
Domanda
boost :: shared_ptr
ha un costruttore insolito
template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p);
e sono un po 'perplesso su cosa potrebbe essere utile. Fondamentalmente condivide la proprietà con r
, ma .get ()
restituirà p
. non r.get ()
!
Ciò significa che puoi fare qualcosa del genere:
int main() {
boost::shared_ptr<int> x(new int);
boost::shared_ptr<int> y(x, new int);
std::cout << x.get() << std::endl;
std::cout << y.get() << std::endl;
std::cout << x.use_count() << std::endl;
std::cout << y.use_count() << std::endl;
}
E otterrai questo:
0x8c66008
0x8c66030
2
2
Nota che i puntatori sono separati, ma entrambi affermano di avere un use_count
di 2 (poiché condividono la proprietà dello stesso oggetto).
Quindi, il int
di proprietà di x
esiste fino a quando x
o y
è in giro. E se ho capito bene i documenti, il secondo int
non viene mai distrutto. Ho confermato questo con il seguente programma di test:
struct T {
T() { std::cout << "T()" << std::endl; }
~T() { std::cout << "~T()" << std::endl; }
};
int main() {
boost::shared_ptr<T> x(new T);
boost::shared_ptr<T> y(x, new T);
std::cout << x.get() << std::endl;
std::cout << y.get() << std::endl;
std::cout << x.use_count() << std::endl;
std::cout << y.use_count() << std::endl;
}
Questo output (come previsto):
T()
T()
0x96c2008
0x96c2030
2
2
~T()
Quindi ... qual è l'utilità di questo insolito costrutto che condivide la proprietà di un puntatore, ma agisce come un altro puntatore (che non possiede) quando usato.
Soluzione
È utile quando si desidera condividere un membro della classe e un'istanza della classe è già un shared_ptr, come il seguente:
struct A
{
int *B; // managed inside A
};
shared_ptr<A> a( new A );
shared_ptr<int> b( a, a->B );
condividono il numero di utilizzo e roba. È l'ottimizzazione per l'utilizzo della memoria.
Altri suggerimenti
Per espandere su leiz's e piotr's risponde, questa descrizione di shared_ptr < >
'aliasing' proviene da un documento del WG21, " Miglioramento di shared_ptr
per C ++ 0x, Revisione 2 " :
III. Supporto aliasing
Gli utenti esperti richiedono spesso il possibilità di creare un
shared_ptr
istanzap
che condivide la proprietà con un altro (master)shared_ptr
q
ma punta a un oggetto che non è una base di* q
.* p
può essere un membro o un elemento di* q
, ad esempio. Questo sezione propone un ulteriore costruttore che può essere utilizzato per questo scopo.Un interessante effetto collaterale di questo l'aumento del potere espressivo è quello ora le funzioni
* _pointer_cast
possono farlo essere implementato nel codice utente. Il Presentazione della funzione di fabbricamake_shared
più avanti in questo documento può anche essere implementato utilizzando solo il pubblico interfaccia dishared_ptr
tramite costruttore aliasing.Impatto:
Questa funzione estende l'interfaccia di
shared_ptr
in un retrocompatibile modo che aumenta il suo espressivo potere ed è quindi fortemente consigliato di essere aggiunto al C ++ 0x standard. Non introduce alcuna fonte e problemi di compatibilità binaria.Testo proposto:
Aggiungi a
shared_ptr
[util.smartptr.shared] quanto segue costruttore:template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );
Aggiungi quanto segue a [Util.smartptr.shared.const]:
<*>Effetti: crea un'istanza
shared_ptr
che memorizzap
e condivide la proprietà conr
.Postcondizioni:
get () == p & amp; & amp; use_count () == r.use_count ()
.Lancia: niente.
[Nota: Per evitare la possibilità di un puntatore penzolante, l'utente di questo costruttore deve assicurarsi che
p
rimanga almeno valido fino alla distruzione del gruppo di proprietà dir
. --end note.][Nota: Questo costruttore consente la creazione di un vuoto
shared_ptr
istanza con un puntatore memorizzato non NULL. --end note.]
Puoi anche usarlo per mantenere i puntatori cast dinamici, cioè:
class A {};
class B: public A {};
shared_ptr<A> a(new B);
shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));
Potresti avere un puntatore ad un driver o ad una struttura di dati dell'API di livello inferiore che può allocare dati aggiuntivi con l'API di livello inferiore o altri mezzi. In questo caso potrebbe essere interessante aumentare use_count ma restituire i dati aggiuntivi se il primo puntatore possiede gli altri puntatori di dati.
Ho messo in uso il costruttore di aliasing di shared_ptr nella mia piccola libreria:
http://code.google.com/p/infectorpp/ (solo il mio contenitore IoC semplice)
Il punto è che da quando avevo bisogno di un shared_ptr di tipo noto per essere restituito da una classe polimorfica (che non conosce il tipo). Non sono stato in grado di convertire implicitamente shared_ptr nel tipo di cui avevo bisogno.
Nel file " InfectorHelpers.hpp " (riga 72-99) puoi vederlo in azione per il tipo IAnyShared.
Il costruttore di aliasing crea shared_ptr che non elimina i puntatori a cui stanno effettivamente puntando, ma aumentano ancora il contatore di riferimento sull'oggetto originale e questo può essere tremendamente utile.
Fondamentalmente puoi creare un puntatore a qualsiasi cosa usando il costruttore di alias e minacciarlo come contatore di riferimento.
//my class
std::shared_ptr<T> ist;
int a; //dummy variable. I need its adress
virtual std::shared_ptr<int> getReferenceCounter(){
return std::shared_ptr<int>(ist,&a); //not intended for dereferencing
}
virtual void* getPtr(); //return raw pointer to T
ora abbiamo entrambi " un contatore di riferimento " e un puntatore a un'istanza di T, dati sufficienti per creare qualcosa con il costruttore di aliasing
std::shared_ptr<T> aPtr( any->getReferenceCounter(), //share same ref counter
static_cast<T*>(any->getPtr()) ); //potentially unsafe cast!
Non pretendo di aver inventato questo uso per il costruttore di aliasing, ma non ho mai visto qualcun altro fare lo stesso. Se stai indovinando se quel codice sporco funziona, la risposta è sì.
Per " shared_ptr < B > b (a, dynamic_cast < B * > (a.get ()));
"
Penso che non sia il modo raccomandato usando il puntatore intelligente.
Il modo consigliato di eseguire questa conversione di tipo dovrebbe essere:
shared_ptr<B> b(a);
Dato che nel documento Boost si dice che:
shared_ptr < T >
può essere implicitamente convertito inshared_ptr < U >
ogni volta che T * può essere implicitamente convertito in U *. Nel in particolare,shared_ptr < T >
è implicitamente convertibile inshared_ptr < T > const
, ashared_ptr < U >
dove U è un base accessibile di T, e ashared_ptr < vuoto >.
Inoltre, abbiamo anche dynamic_pointer_cast che potrebbe effettuare direttamente la conversione sull'oggetto Puntatore intelligente ed entrambi questi due metodi sarebbero molto più sicuri rispetto al modo puntatore non elaborato di cast manuale.