2012-04-05 11 views
6

Ho una classe che contiene un elenco contenente boost::shared_ptrs per oggetti di un'altra classe.Contenitore di shared_ptr ma iterazione con puntatori raw

Le funzioni membro della classe che danno accesso agli elemeti nell'elenco restituiscono puntatori non elaborati. Per coerenza mi piacerebbe anche essere in grado di scorrere con puntatori raw invece di shared_ptrs. Quindi, quando denuncio l'elenco iteratore, mi piacerebbe ottenere un puntatore raw, non uno shared_ptr.

Suppongo di dover scrivere un iteratore personalizzato per questo. È corretto? Se è così, qualcuno può indicarmi la giusta direzione - non l'ho mai fatto prima.

+1

Ricorda che l'azione di 'shared_ptr' come normali puntatori (' * p' e 'p->' entrambi fanno The Right Thing). – GManNickG

+0

Potrei sbagliarmi, ma fornire sia un puntatore raw che un puntatore intelligente sembra come chiedere dei problemi. In particolare, se i puntatori grezzi consentono le scritture. Che tipo di iteratori stai cercando? Se fossi in te, probabilmente inizierei con il più semplice come "ForwardIterator". – dirkgently

+0

So che 'shared_ptr' ha lo stesso comportamento con' * p' e 'p->'. Per un po 'non mi importava davvero la differenza. Ma è un problema quando si tratta dell'interfaccia utente. Altre funzioni nell'API prendono i puntatori come argomenti. Quindi se l'utente ottiene l'oggetto da un iteratore, allora deve usare 'it-> get()' per ottenere il puntatore raw. Suppongo che non importi molto, ma dal punto di vista dell'utente finale, non c'è alcun motivo per cui l'utente dovrebbe anche sapere che l'oggetto sottostante è tenuto da un 'shared_ptr'. Quindi mi piacerebbe renderlo coerente attraverso la biblioteca. –

risposta

5

Ecco un'opzione usando Boost transform_iterator:

#include <list> 
#include <boost/iterator/transform_iterator.hpp> 
#include <tr1/memory> 
#include <tr1/functional> 

using std::list; 
using std::tr1::shared_ptr; 
using boost::transform_iterator; 
using boost::make_transform_iterator; 
using std::tr1::mem_fn; 
using std::tr1::function; 

struct Foo {}; 

struct Bar 
{ 
    typedef shared_ptr<Foo> Ptr; 
    typedef list<Ptr> List; 
    typedef function< Foo* (Ptr) > Functor; 
    typedef transform_iterator< Functor, List::iterator > Iterator; 

    Iterator begin() 
    { 
    return make_transform_iterator(fooptrs.begin(), mem_fn(&Ptr::get)); 
    } 

    Iterator end() 
    { 
    return make_transform_iterator(fooptrs.end(), mem_fn(&Ptr::get)); 
    } 

    List fooptrs; 
}; 

C++ 11 lo rendono facile da eliminare la function involucro, ma io non ho un compilatore a portata di mano di provarlo. Si potrebbe anche nascondere il tipo concreto di Iterator usando tipo cancellazione se avete visto il bisogno (penso che Adobe offre un libero any_iterator modello di classe per questo scopo.)

+2

+1, e se ottenere riferimenti anziché puntatori era accettabile (e non vedo perché non dovrebbe essere), Boost viene fornito anche con ['indirect_iterator <>'] (http://www.boost.org/ libs/iteratore/doc/indirect_iterator.html). – ildjarn

+0

Perfetto. Ottima risposta con un ottimo esempio. –

1

volte vedo persone di raggiungere per i contenitori STL di boost::shared_ptr quando in realtà il boost::ptr_container meno ovvio e relativamente poco conosciuto potrebbe essere una scelta migliore.

Questo può o non può essere uno di questi casi, ma considera che una delle buone proprietà delle classi ptr_container è che i loro iteratori hanno an "extra" indirection che aiuta a mantenere le cose pulite e sicure.

+0

Sì, è vero. In questo caso, tuttavia, la proprietà sarà effettivamente condivisa. –

Problemi correlati