I have a class that holds a list containing boost::shared_ptrs
to objects of another class.
The class member functions that give access to the elemets in the list return raw pointers. For consistency I'd also like to be able to iterate with raw pointers instead of shared_ptrs. So when I dereference the list iterator, I'd like to get raw pointer, not a shared_ptr
.
I assume I need to write a custom iterator for this. Is this correct? If so can someone point me in the right direction - I've never done this before.
ForwardIterator
- dirkgently 2012-04-05 21:07
shared_ptr
's behave the same with *p
and p->
. For a while I didn't really mind the difference. But it's a problem when it comes to the user interface. Other functions in the API take pointers as arguments. So if the user gets the object from an iterator he then needs to use it->get()
to get the raw pointer. I suppose it doesn't matter much but from an end-user standpoint, there's no reason why the user should even know that the underlying object is held by a shared_ptr
. So I'd like to make it consistent across the library - Sean Lynch 2012-04-05 21:14
p
(for raw-pointers) to *pi
(special iterators whose dereference operation provides the raw pointer). He'd still get to know something about your underlying representation. Or, am I missing something - dirkgently 2012-04-05 21:23
Here's an option using 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 would make it easy to eliminate the function
wrapper but I don't have a compiler handy to test it out. You could also hide the concrete type of Iterator
using type-erasure if you saw the need (I think Adobe offers a free any_iterator
class template for this purpose.)
I sometimes see people reaching for STL containers of boost::shared_ptr
when actually the less obvious and relatively little known boost::ptr_container
might be a better choice.
This may or may not be one of those cases, but consider that one of the nice properties of the ptr_container
classes is that their iterators have an "extra" indirection which helps keep things clean and safe.
shared_ptr
's act like regular pointers (*p
andp->
both do The Right Thing) - GManNickG 2012-04-05 20:56