2012-04-05 8 views
6

Tengo una clase que contiene una lista que contiene boost::shared_ptrs a objetos de otra clase.Contenedor de shared_ptr pero iterar con punteros sin formato

Las funciones miembro de clase que dan acceso a los elemets en la lista devuelven punteros sin formato. Para mayor coherencia, también me gustaría poder iterar con punteros sin formato en lugar de shared_ptrs. Así que cuando elimine la referencia del iterador de la lista, me gustaría obtener un puntero sin formato, no un shared_ptr.

Supongo que necesito escribir un iterador personalizado para esto. ¿Es esto correcto? Si es así, ¿puede alguien señalarme en la dirección correcta? Nunca he hecho esto antes.

+1

Tenga en cuenta que 'shared_ptr' actúa como punteros regulares (' * p' y 'p->' ambos hacen Lo correcto). – GManNickG

+0

Puedo estar equivocado, pero proporcionar tanto un puntero sin formato como un puntero inteligente parece ser un problema. Particularmente, si los punteros sin procesar permiten escrituras. ¿Qué tipo de iteradores estás buscando? Si yo fuera tú, probablemente comenzaría con el más simple, como el 'ForwardIterator'. – dirkgently

+0

Sé que 'shared_ptr' tiene el mismo comportamiento con' * p' y 'p->'. Por un tiempo, realmente no me importó la diferencia. Pero es un problema cuando se trata de la interfaz de usuario. Otras funciones en la API toman punteros como argumentos. Entonces, si el usuario obtiene el objeto de un iterador, entonces necesita usar 'it-> get()' para obtener el puntero sin procesar. Supongo que no importa mucho, pero desde el punto de vista del usuario final, no hay ninguna razón por la que el usuario deba siquiera saber que el objeto subyacente está en un 'shared_ptr'. Entonces me gustaría hacer que sea consistente en toda la biblioteca. –

Respuesta

5

Aquí es una opción mediante 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 haría más fácil para eliminar la envoltura function pero no tengo un compilador útil para probarlo. También podría ocultar el tipo concreto de Iterator usando tipo de borrado si usted vio la necesidad (creo que Adobe ofrece una plantilla libre any_iterator clase para este propósito.)

+2

+1, y si obtener referencias en lugar de punteros era aceptable (y no veo por qué no debería ser), Boost también viene con ['indirect_iterator <>'] (http://www.boost.org/ libs/iterator/doc/indirect_iterator.html). – ildjarn

+0

Perfecto. Gran respuesta con gran ejemplo. –

1

veces veo a la gente para llegar a contenedores STL de boost::shared_ptr cuando en realidad el menos obvio y relativamente poco conocido boost::ptr_container podría ser una mejor opción.

Esto puede o no ser uno de esos casos, pero considere que una de las buenas propiedades de las clases ptr_container es que sus iteradores tienen an "extra" indirection que ayuda a mantener las cosas limpias y seguras.

+0

Sí, eso es cierto. En este caso, sin embargo, habrá propiedad compartida. –

Cuestiones relacionadas