shared_ptr的容器,但使用原始指针进行迭代

时间:2012-04-05 20:38:58

标签: c++ iterator

我有一个类,其中包含一个包含boost::shared_ptrs的列表到另一个类的对象。

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

我假设我需要为此编写一个自定义迭代器。它是否正确?如果是这样,有人能指出我正确的方向 - 我以前从未这样做过。

3 个答案:

答案 0 :(得分: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类模板。)

答案 1 :(得分:1)

我有时会看到人们到达boost::shared_ptr的STL容器时实际上不那么明显且相对鲜为人知的boost::ptr_container可能是更好的选择。

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

答案 2 :(得分:0)

?‍♀️ ...僵尸线...?

如果您无法使用Boost(例如,它是您的公共界面的一部分,并且您不想对用户提出此要求),则可以相对轻松地推出自己的产品。对于容器my_container-可能是标准的boost容器,无论其实际实现隐藏在实现文件中而不暴露给您的API的任何容器-保留指向类{{ 1}},就像这样:

my_type

在cpp文件中,假设我们在幕后使用class iterator { public: ~iterator(); iterator( const iterator& other ); iterator& operator=( const iterator& other ); // The standard iterator traits (names must be lower-case) typedef std::forward_iterator_tag iterator_category; typedef my_type* value_type; typedef std::ptrdiff_t difference_type; typedef value_type* pointer; typedef value_type reference; iterator& operator++(); iterator& operator++( int ); reference operator*() const; friend bool operator==( const iterator& it1, const iterator& it2 ); friend bool operator!=( const iterator& it1, const iterator& it2 ); private: // Private, type-erased construction friend class my_container; explicit iterator( void* ); // Implementation hidden by pimpl struct impl; impl* _impl; }; 中的vector

shared_ptr

然后,您所需要做的就是创建这些方法。为此,// Define the Pimpl struct struct iterator::impl { typedef std::vector< std::shared_ptr<my_type> >::iterator iterator; iterator iter; }; // Use void* as type erasure to hide the actual types from the user iterator::iterator( void* wrappedIter ) : _impl( new impl( *reinterpret_cast<impl::iterator*>( wrappedIter ) ) ) { } // Copying iterator::iterator( const iterator& other ) : _impl( new impl( *other._impl ) ) {} iterator& iterator::operator=( const iterator& other ) { _impl->iter = other._impl->iter; return *this; } // ... could implement moving too ... iterator::~iterator() { // Destroy the pimpl delete _impl; } iterator& iterator::operator++() { ++_impl->iter; return *this; } iterator& iterator::operator++( int ) { ++_impl->iter; return *this; } iterator::reference iterator::operator*() const { // This is where the magic happens: We convert the shared_ptr to a raw pointer. return _impl->iter->second.get(); } bool operator==( const iterator& it1, const iterator& it2 ) { return *it1 == *it2; } bool operator!=( const iterator& it1, const iterator& it2 ) { return !( it1 == it2 ); } 的{​​{1}} / my_container函数如下所示:

begin()

那种类型的擦除并获取一个成员变量的地址看起来有点麻烦,但这没关系,因为我们立即重新解释end()并取消引用和复制它。