2010-01-27 13 views
17

Ho alcune domande sulle migliori pratiche di utilizzo di shared_ptr.Domande sugli usi di shared_ptr - C++

Domanda 1

sta copiando shared_ptr a buon mercato? O devo passare come riferimento alle mie proprie funzioni di supporto e restituire come valore? Qualcosa di simile,

void init_fields(boost::shared_ptr<foo>& /*p_foo*/); 
void init_other_fields(boost::shared_ptr<foo>& /*p_foo*/); 

boost::shared_ptr<foo> create_foo() 
{ 
    boost::shared_ptr<foo> p_foo(new foo); 
    init_fields(p_foo); 
    init_other_fields(p_foo); 
} 

Domanda 2

Devo usare boost::make_shared per costruire un shared_ptr? Se sì, quali vantaggi offre? E come possiamo usare make_shared quando T non ha un costruttore parametrico?

Domanda 3

Come usare const foo*? Ho trovato due approcci per farlo.

void take_const_foo(const foo* pfoo) 
{ 

} 

int main() 
{ 
    boost::shared_ptr<foo> pfoo(new foo); 
    take_const_foo(pfoo.get()); 
    return 0; 
} 

O

typedef boost::shared_ptr<foo> p_foo; 
typedef const boost::shared_ptr<const foo> const_p_foo; 

void take_const_foo(const_p_foo pfoo) 
{ 

} 

int main() 
{ 
    boost::shared_ptr<foo> pfoo(new foo); 
    take_const_foo(pfoo); 
    return 0; 
} 

Domanda 4

Come posso tornare e verificare la presenza di NULL su un oggetto shared_ptr? È qualcosa di simile,

boost::shared_ptr<foo> get_foo() 
{ 
    boost::shared_ptr<foo> null_foo; 
    return null_foo; 
} 

int main() 
{ 
    boost::shared_ptr<foo> f = get_foo(); 
    if(f == NULL) 
    { 
      /* .. */ 
    } 
    return 0; 
} 

Qualsiasi aiuto sarebbe grande.

+2

La documentazione hanno una pagina di temporizzazione: http://www.boost.org/doc/libs/1_41_0/libs/smart_ptr/smarttests.htm –

risposta

8

La maggior parte delle domande hanno avuto risposta, ma io non sono d'accordo sul fatto che una copia shared_ptr sia economica.

Una copia ha semantica diversa da un passaggio per riferimento. Modificherà il conteggio dei riferimenti, che attiverà un incremento atomico nel migliore dei casi e un blocco nel caso peggiore. Devi decidere quale semantica hai bisogno e poi saprai se passare per riferimento o per valore.

Dal punto di vista delle prestazioni, in genere è consigliabile utilizzare un contenitore di puntatori boost anziché un contenitore di shared_ptr.

+0

Sì, hai ragione, copiare i puntatori ref-counted può essere costoso! +1 – sbi

2
  1. Uno dei motivi fondamentali dell'esistenza di shared_ptr è di essere relativamente economico da copiare.
  2. Esistono versioni di make_shared che accettano parametri (e se il compilatore supporta modelli variadic, uno che accetta un elenco di parametri variabili).
  3. Sembra che tu stia cercando const_ptr_cast?
  4. Per restituire un puntatore nullo, è possibile passare '0' al conduttore share_ptr. Per verificare la presenza di un puntatore nullo, è possibile confrontare p.get() per 0.
+7

Re 4 #: Non fa 'if (f)'/'if (! f)' funziona? – sbi

+0

per # 4: puoi confrontare 'p' con 0 come pure – laura

+0

@sbi e laura: sì, è vero che ha le conversioni integrate, quindi il più delle volte puoi trattarlo come se fosse un normale puntatore. –

3
  1. Sì, la copia è assolutamente a buon mercato. Oltre a contenere il puntatore, c'è (di solito) un altro membro dati per la classe shared_ptr - il conteggio degli usi.
  2. Non posso rispondere a questa, io in genere utilizzare versioni spinta prima make_shared è stato introdotto (1,40?)
  3. Usa boost :: const_pointer_cast
  4. shared_ptr ha operatore == /! = Definito. Nel tuo esempio sopra: if (f)
4
  1. copia è a buon mercato, il puntatore non prende molto spazio. L'obiettivo principale era renderlo piccolo per consentire l'utilizzo in contenitori in base al valore (ad esempio std::vector< shared_ptr<Foo> >).

  2. make_shared accetta una quantità variabile di parametri ed è la meccanica preferita per la costruzione di se stessi (proprio come make_pair). Il vantaggio è la leggibilità, soprattutto se provvisori e/o spazi dei nomi di passaggio è coinvolto:

  3. boost::const_ptr_cast come già suggerito

  4. puntatori intelligenti sono sovraccaricato gli operatori e possono essere utilizzati direttamente nelle espressioni valutate al bool. Non utilizzare get. Per qualsiasi cosa. Invece di confrontare p.get a nulla, confrontare un'istanza puntatore vuoto (my_ptr != boost::shared_ptr<MyClass>())

AD.2

func_shared(boost::shared_ptr<my_tools::MyLongNamedClass>( 
    new my_tools::MyLongNamedClass(param1, param2)); 

contro

func_shared(boost::make_shared<my_tools::MyLongNamedClass>(param1, param2)); 
+0

Il vantaggio * maggiore * di 'make_shared' non è la leggibilità, ma l'efficienza:' shared_ptr' richiede l'allocazione dinamica della memoria per il conteggio dei riferimenti condivisi, in modo che 'shared_ptr <...> (nuovo ...)' implichi due (spesso costose) allocazioni di memoria . 'make_shared', d'altra parte, alloca memoria sufficiente per l'oggetto più il conteggio dei riferimenti allo stesso tempo, ed è quindi più efficiente. –

3
  1. La copia di un parametro shared_ptr ora costa 32 byte in copia stack e incrementi/decrementi extra del conteggio. Decidi se è economico per te o no, ma non vedo alcun motivo per non passare un riferimento const, in particolare che hai già un typedef per il ptr: void f(const foo_ptr &myfoo) specialmente dato che il parametro standard di non scrittura-scrittura passa in C++ è un riferimento const.

  2. Preferirei non avere funzioni che accettano puntatore che non è condiviso. Questo è simile (anche se non identico) al parametro che passa la semantica in Java e C#. Perché immergersi nel decidere ogni volta come passare un oggetto, invece di avere un modo standard per farlo?

  3. Utilizzare if(p) come per i puntatori regolari. La semantica della conversione booleana è piuttosto accurata.

Problemi correlati