2013-05-08 8 views
11

私は長年にわたって問題なく使用してきたカスタムコンテナを持っています。最近、コンテナのイテレータを定義すると、<algorithm>で定義されているすべてのアルゴリズムを効果的に使用できることが分かりました。それだけでなく、thrust library(基本的にはNvidia GPUのSTLのCUDAバージョンと思われます)はイテレータを頻繁に使用しているようですが、それらを使用することでそのライブラリも使用できることを期待しています。カスタムコンテナのSTL互換イテレータ

これは私自身のイテレーターを書くのが私の最初の試みなので、私はここにあるものを投稿して、さらに援助を求めて、自分のしていることが正しいことを確認すると思った。だから、私はiteratorconst_iteratorクラスの両方をサポートする小さな配列クラスを書いています。私はクラスのSTLアルゴリズムをたくさん使って走っていて、すべてうまくいくように見えますが、必ずしもすべてが正しいとは限りません!特に、私のイテレータに間違っている演算子がありますか? 余分な不要なものを定義しましたか?また、iteratorconst_iteratorのほとんどが類似しているので、重複を防ぐ方法はありますか?

私が提案や改善に開いている:)

ライブ例:http://ideone.com/7YdiQY

#include <cstddef> 
#include <iostream> 
#include <iterator> 
#include <algorithm> 

template<typename T> 
class my_array{ 
    T* data_; 
    std::size_t size_; 

public: 

    // --------------------------------- 
    // Forward declaration 
    // --------------------------------- 
    class const_iterator; 

    // --------------------------------- 
    // iterator class 
    // --------------------------------- 
    class iterator: public std::iterator<std::random_access_iterator_tag, T> 
    { 
    public: 
     iterator(): p_(NULL) {} 
     iterator(T* p): p_(p) {} 
     iterator(const iterator& other): p_(other.p_) {} 
     const iterator& operator=(const iterator& other) {p_ = other.p_; return other;} 

     iterator& operator++() {p_++; return *this;} // prefix++ 
     iterator operator++(int) {iterator tmp(*this); ++(*this); return tmp;} // postfix++ 
     iterator& operator--() {p_--; return *this;} // prefix-- 
     iterator operator--(int) {iterator tmp(*this); --(*this); return tmp;} // postfix-- 

     void  operator+=(const std::size_t& n) {p_ += n;} 
     void  operator+=(const iterator& other) {p_ += other.p_;} 
     iterator operator+ (const std::size_t& n) {iterator tmp(*this); tmp += n; return tmp;} 
     iterator operator+ (const iterator& other) {iterator tmp(*this); tmp += other; return tmp;} 

     void  operator-=(const std::size_t& n) {p_ -= n;} 
     void  operator-=(const iterator& other) {p_ -= other.p_;} 
     iterator operator- (const std::size_t& n) {iterator tmp(*this); tmp -= n; return tmp;} 
     std::size_t operator- (const iterator& other) {return p_ - other.p_;} 

     bool operator< (const iterator& other) {return (p_-other.p_)< 0;} 
     bool operator<=(const iterator& other) {return (p_-other.p_)<=0;} 
     bool operator> (const iterator& other) {return (p_-other.p_)> 0;} 
     bool operator>=(const iterator& other) {return (p_-other.p_)>=0;} 
     bool operator==(const iterator& other) {return p_ == other.p_; } 
     bool operator!=(const iterator& other) {return p_ != other.p_; } 

     T& operator[](const int& n) {return *(p_+n);} 
     T& operator*() {return *p_;} 
     T* operator->(){return p_;} 

    private: 
     T* p_; 

     friend class const_iterator; 
    }; 

    // --------------------------------- 
    // const_iterator class 
    // --------------------------------- 
    class const_iterator: public std::iterator<std::random_access_iterator_tag, T> 
    { 
    public: 
     const_iterator(): p_(NULL) {} 
     const_iterator(const T* p): p_(p) {} 
     const_iterator(const iterator& other): p_(other.p_) {} 
     const_iterator(const const_iterator& other): p_(other.p_) {} 
     const const_iterator& operator=(const const_iterator& other) {p_ = other.p_; return other;} 
     const const_iterator& operator=(const iterator& other) {p_ = other.p_; return other;} 

     const_iterator& operator++() {p_++; return *this;} // prefix++ 
     const_iterator operator++(int) {const_iterator tmp(*this); ++(*this); return tmp;} // postfix++ 
     const_iterator& operator--() {p_--; return *this;} // prefix-- 
     const_iterator operator--(int) {const_iterator tmp(*this); --(*this); return tmp;} // postfix-- 

     void   operator+=(const std::size_t& n)    {p_ += n;} 
     void   operator+=(const const_iterator& other)  {p_ += other.p_;} 
     const_iterator operator+ (const std::size_t& n)  const {const_iterator tmp(*this); tmp += n; return tmp;} 
     const_iterator operator+ (const const_iterator& other) const {const_iterator tmp(*this); tmp += other; return tmp;} 

     void   operator-=(const std::size_t& n)    {p_ -= n;} 
     void   operator-=(const const_iterator& other)  {p_ -= other.p_;} 
     const_iterator operator- (const std::size_t& n)  const {const_iterator tmp(*this); tmp -= n; return tmp;} 
     std::size_t operator- (const const_iterator& other) const {return p_ - other.p_;} 

     bool operator< (const const_iterator& other) const {return (p_-other.p_)< 0;} 
     bool operator<=(const const_iterator& other) const {return (p_-other.p_)<=0;} 
     bool operator> (const const_iterator& other) const {return (p_-other.p_)> 0;} 
     bool operator>=(const const_iterator& other) const {return (p_-other.p_)>=0;} 
     bool operator==(const const_iterator& other) const {return p_ == other.p_; } 
     bool operator!=(const const_iterator& other) const {return p_ != other.p_; } 

     const T& operator[](const int& n) const {return *(p_+n);} 
     const T& operator*() const {return *p_;} 
     const T* operator->() const {return p_;} 

    private: 
     const T* p_; 
    }; 

    my_array() 
     : data_(NULL), size_(0) 
    {} 
    my_array(std::size_t size) 
     : data_(new T[size]), size_(size) 
    {} 
    my_array(const my_array<T>& other){ 
     size_ = other.size_; 
     data_ = new T[size_]; 
     for (std::size_t i = 0; i<size_; i++) 
      data_[i] = other.data_[i]; 
    } 
    my_array(const const_iterator& first, const const_iterator& last){ 
     size_ = last - first; 
     data_ = new T[size_]; 

     for (std::size_t i = 0; i<size_; i++) 
      data_[i] = first[i]; 
    } 

    ~my_array(){ 
     delete [] data_; 
    } 
    const my_array<T>& operator=(const my_array<T>& other){ 
     size_ = other.size_; 
     data_ = new T[size_]; 
     for (std::size_t i = 0; i<size_; i++) 
      data_[i] = other.data_[i]; 
     return other; 
    } 
    const T& operator[](std::size_t idx) const {return data_[idx];} 
    T& operator[](std::size_t& idx) {return data_[idx];} 
    std::size_t size(){return size_;} 

    iterator begin(){ return iterator(data_); } 
    iterator end() { return iterator(data_+size_); } 
    const_iterator begin() const{ return const_iterator(data_); } 
    const_iterator end() const { return const_iterator(data_+size_);} 
}; 

template<typename T> 
void print(T t) { 
    std::cout << t << std::endl; 
} 

int main(){ 

    // works! 
    int list [] = {1, 3, 5, 2, 4, 3, 5, 10, 10}; 
    my_array<int> a(list, list+sizeof(list)/sizeof(int)); 

    // works! 
    for (my_array<int>::const_iterator it = a.begin(), end = a.end(); 
     it != end; ++it) 
     std::cout << ' ' << *it; 
    std::cout << std::endl; 

    // works! 
    std::for_each(a.begin(), a.end(), print<int>); 
    std::cout << std::endl; 

    // works! 
    my_array<int> b(a.size()); 
    std::copy(a.begin(), a.end(), b.begin()); 

    // works! 
    my_array<int>::iterator end = std::remove(a.begin(), a.end(), 5); 
    std::for_each(a.begin(), end, print<int>); 
    std::cout << std::endl; 

    // works! 
    std::random_shuffle(a.begin(), end); 
    std::for_each(a.begin(), end, print<int>); 
    std::cout << std::endl; 

    // works! 
    std::cout << "Counts of 3 in array = " << std::count(a.begin(), end, 3) << std::endl << std::endl; 

    // works! 
    std::sort(a.begin(), end); 
    std::for_each(a.begin(), end, print<int>); 
    std::cout << std::endl; 

    // works! 
    if (!std::binary_search(a.begin(), a.end(), 5)) 
     std::cout << "Removed!" << std::endl; 

    return 0; 
} 
+8

私はあなたがhttp://codereview.stackexchange.com/を望んでいると思っています。標準ライブラリ互換イテレータの要件のリスト(The Standardよりも読みやすい)リストが必要な場合は、[here](http:// en。 cppreference.com/w/cpp/concept/RandomAccessIterator)。 – BoBTFish

+0

@BoBTFish多くの人が同じように考えるなら、私は移行できます。私は人々がそれをやっているのを見ましたが、私はどうしたらよいか分かりません。 – GradGuy

+0

'cbegin'と' cend'を追加することをお勧めします。 – BoBTFish

答えて

3

boost iteratorは、STLに準拠したイテレータを作成し、既存のものを適応するためのフレームワークを提供します。

これは、機能に焦点を当てて、必要なすべての特性、typedefを生成します。

iteratorおよびconst_iteratorコードの重複をほとんど作らずに作成できます。

1

ブーストiterator_adaptorは、コードを大幅に簡素化できます。 documentationは、リンクされたリスト反復子の例では、デフォルトのコンストラクタ、ノードポインタのみノードポインタに変換することができる要素を受け入れる一般コピーコンストラクタをとるコンストラクタを提供すること

template <class Value> 
class node_iter 
    : public boost::iterator_adaptor< 
     node_iter<Value>    // Derived 
     , Value*       // Base 
     , boost::use_default    // Value 
     , boost::forward_traversal_tag // CategoryOrTraversal 
    > 
{ 
private: 
    struct enabler {}; // a private type avoids misuse 

public: 
    node_iter() 
     : node_iter::iterator_adaptor_(0) {} 

    explicit node_iter(Value* p) 
     : node_iter::iterator_adaptor_(p) {} 

    template <class OtherValue> 
    node_iter(
     node_iter<OtherValue> const& other 
     , typename boost::enable_if< 
      boost::is_convertible<OtherValue*,Value*> 
      , enabler 
     >::type = enabler() 
    ) 
     : node_iter::iterator_adaptor_(other.base()) {} 

private: 
    friend class boost::iterator_core_access; 
    void increment() { this->base_reference() = this->base()->next(); } 
}; 

注、およびのためにこの例インクリメント機能。インクリメント機能は、operator++()operator++(int)の両方で共有される実装の詳細です。

他のすべてのボイラープレートは、boost::iterator_adaptorから派生して自動的に生成されます。これには、std::iteratorから派生したネストされたすべてのtypedefと、すべてのオーバーロードされた演算子(++、*、 - >、==、!=、advance)イテレータ。

Value const*を渡し、typedefを使用すると、すべてのコードを適切な変更で再利用するconst_iteratorを定義できます。この例を勉強すれば、あなたは道のりを大いに救うでしょう。