2012-04-05 76 views
6

我有一个类,其中包含boost::shared_ptrs到另一个类的对象的列表。shared_ptr的容器,但迭代原始指针

允许访问列表中的元素的类成员函数返回原始指针。为了一致性,我还希望能够使用raw指针而不是shared_ptrs进行迭代。所以当我解引用列表迭代器时,我想获取原始指针,而不是shared_ptr

我想我需要为此编写一个自定义迭代器。它是否正确?如果有的话可以有人指出我正确的方向 - 我从来没有这样做过。

+1

请记住,'shared_ptr'就像常规指针('* p'和'p->'都做正确的事情)。 – GManNickG 2012-04-05 20:56:53

+0

我可能是错的,但提供原始指针和智能指针看起来像是在寻找麻烦。特别是,如果原始指针允许写入。你在寻找什么样的迭代器?如果我是你,我可能会从最简单的例如'ForwardIterator'开始。 – dirkgently 2012-04-05 21:07:10

+0

我知道'shared_ptr'与'* p'和'p->'表现得一样。有一段时间,我并没有真正意识到差异。但是当涉及到用户界面时,这是一个问题。 API中的其他函数将指针作为参数。因此,如果用户从迭代器获取对象,则需要使用'it-> get()'获取原始指针。我认为这并不重要,但从最终用户的角度来看,用户甚至不应该知道底层对象由'shared_ptr'保存。所以我想在整个图书馆中保持一致。 – 2012-04-05 21:14:26

回答

5

下面是一个使用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就可以很容易地消除function包装,但我没有方便的编译器来测试它。你也可以使用类型擦除,如果你认为有必要隐藏了具体类型的Iterator(我认为Adobe提供免费的any_iterator类模板用于此目的。)

+2

+1,如果获得引用而不是指针是可以接受的(我不明白为什么它不应该是这样),Boost也带有['indirect_iterator <>'](http://www.boost.org/库/迭代器/ DOC/indirect_iterator.html)。 – ildjarn 2012-04-05 22:11:44

+0

完美。很好的例子,很好的答案。 – 2012-04-07 00:01:35

1

我有时看到有人伸手的boost::shared_ptr STL容器时,实际上不太明显且相对较少的已知boost::ptr_container可能是更好的选择。

这可能是也可能不是这种情况之一,但考虑到ptr_container类的一个很好的属性是它们的迭代器有an "extra" indirection,这有助于保持事物的清洁和安全。

+0

是的,这是真的。然而,在这种情况下,实际上会共享所有权。 – 2012-04-05 23:59:30