6

boost::shared_ptrs別のクラスのオブジェクトを含むリストを保持するクラスがあります。

リスト内の要素へのアクセスを提供するクラスメンバー関数は、生のポインターを返します。一貫性を保つために、shared_ptrsの代わりにrawポインターを使用して反復できるようにしたいと思います。したがって、リストイテレータを逆参照するときは、ではなく生のポインタを取得したいと思いますshared_ptr

このためにカスタムイテレータを作成する必要があると思います。これは正しいです?もしそうなら、誰かが私を正しい方向に向けることができます-私はこれまでこれをしたことがありません。

4

3 に答える 3

5

Boosttransform_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ますが、テストするのに便利なコンパイラーがありません。必要に応じて、型消去を使用する具体的なタイプを非表示にすることもできます(Adobeはこの目的のためにIterator無料のクラステンプレートを提供していると思います)。any_iterator

于 2012-04-05T21:39:20.153 に答える
1

私は時々人々がSTLコンテナに手を伸ばすのを見ますがboost::shared_ptr、実際にはあまり明白ではなく、比較的あまり知られていboost::ptr_containerない方が良い選択かもしれません。

これはそのような場合の1つである場合とそうでない場合がありますが、ptr_containerクラスの優れた特性の1つは、イテレータに「余分な」間接参照があり、物事をクリーンで安全に保つのに役立つことです。

于 2012-04-05T23:24:04.553 に答える
0

‍♀️...ゾンビスレッド..。

Boostを使用できない場合(たとえば、それがパブリックインターフェイスの一部であり、それをユーザーの要件にしたくない場合)、比較的簡単に自分でロールすることができます。コンテナmy_container(標準、ブースト、どのコンテナでもフロントになる可能性がありますが、実際の実装は実装ファイルに隠されており、APIには公開されていません)の場合、クラスへのスマートポインタを保持するmy_typeと、次のようになります。

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そして、cppファイルでは、内部でのを使用していると仮定します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 ); 
}

次に必要なのは、これらを作成する方法です。そのために、my_container's begin()/end()関数は次のようになります。

my_container::iterator my_container::begin()
{
    // The & allows our type erasure by invoking our void* constructor
    auto iter = _data->vector.begin();
    return iterator( &iter );
}

my_container::iterator my_container::end()
{
    // The & allows our type erasure by invoking our void* constructor
    auto iter = _data->vector.end();
    return iterator( &iter );
}

その型消去とメンバー変数のアドレスの取得は少し厄介な見た目ですが、すぐに再解釈しvoid*、逆参照してコピーするので問題ありません。

于 2019-11-29T22:01:27.653 に答える