♀️...ゾンビスレッド..。
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*
、逆参照してコピーするので問題ありません。