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.

È stato utile?

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   istanza p 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 fabbrica make_shared   più avanti in questo documento può anche essere   implementato utilizzando solo il pubblico   interfaccia di shared_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 memorizza p e condivide la proprietà con r .

         

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à di r . --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 in shared_ptr < U > ogni volta che T *   può essere implicitamente convertito in U *. Nel   in particolare, shared_ptr < T > è   implicitamente convertibile in shared_ptr < T > const ,   a shared_ptr < U > dove U è un   base accessibile di T, e a    shared_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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top