Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Container of shared_ptr's but iterate with raw pointers

Tags:

c++

iterator

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.

like image 615
Sean Lynch Avatar asked Apr 05 '12 20:04

Sean Lynch


People also ask

Is shared_ ptr a pointer?

The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner might have to manage the lifetime of the object in memory.

When to use shared_ ptr?

Use shared_ptr to manage the lifetime of objects: Whose ownership is shared (multiple "things" want the object lifetime extended) Where the order of release of ownership is non-deterministic (you don't know in advance which of the owners will be "last" to release the object).

How to define a shared pointer in c++?

Shared pointers in C++ In C++, a shared pointer is one of the smart pointers. The shared pointer maintains a reference count which is incremented when another shared pointer points to the same object. So, when the reference count is equal to zero (i.e., no pointer points to this object), the object is destroyed.


2 Answers

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.)

like image 117
Andrew Durward Avatar answered Oct 06 '22 14:10

Andrew Durward


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.

like image 25
timday Avatar answered Oct 06 '22 14:10

timday