如何正确地实现自定义迭代器和const_iterator?

我有一个自定义的容器类,我想写的iteratorconst_iterator类。

我从来没有这样做,我没有find一个合适的方法。 关于迭代器创build的准则是什么?我应该注意什么?

我也想避免代码重复(我觉得const_iteratoriterator共享很多东西;一个子类应该是另一个?)。

脚注:我非常确定,Boost有一些可以缓解这个问题的方法,但是由于许多愚蠢的原因,我无法在这里使用它。

  • select适合你的容器的迭代器的types:input,输出,转发等
  • 使用标准库中的基本迭代器类。 例如,带有random_access_iterator_tag std::iterator 。这些基类定义了STL所需的所有types定义,并执行其他工作。
  • 为了避免代码重复,迭代器类应该是一个模板类,并通过“值types”,“指针types”,“引用types”或全部(取决于实现)进行参数化。 例如:

     // iterator class is parametrized by pointer type template <typename PointerType> class MyIterator { // iterator class definition goes here }; typedef MyIterator<int*> iterator_type; typedef MyIterator<const int*> const_iterator_type; 

    注意iterator_typeconst_iterator_typetypes定义:它们是非常量和常量迭代器的types。

另请参见: 标准库引用

我将向您展示如何为您的自定义容器轻松定义迭代器,但是为了防止我创build了一个c ++ 11库,使您可以轻松地为任何types的容器创build具有自定义行为的自定义迭代器,连续或非constiguous。

你可以在https://github.com/navyenzo/blIteratorAPI的; github上find它

以下是创build和使用自定义迭代器的简单步骤:

  1. 创build你的“自定义迭代器”类。
  2. 在“自定义容器”类中定义typedef。
    • 例如: typedef blRawIterator< Type > iterator;
    • 例如: typedef blRawIterator< const Type > const_iterator;
  3. 定义“开始”“结束”function
    • 例如: iterator begin(){return iterator(&m_data[0]);};
    • 例如: const_iterator cbegin()const{return const_iterator(&m_data[0]);};
  4. 我们已经完成了!

最后,定义我们的自定义迭代器类:

注意: 定义自定义迭代器时,我们从标准迭代器类别派生,让STLalgorithm知道我们所做的迭代器的types

在这个例子中,我定义了一个随机访问迭代器和一个反向随机访问迭代器:

1。

 //------------------------------------------------------------------- // Raw iterator with random access //------------------------------------------------------------------- template<typename blDataType> class blRawIterator : public std::iterator<std::random_access_iterator_tag, blDataType, ptrdiff_t, blDataType*, blDataType&> { public: blRawIterator(blDataType* ptr = nullptr){m_ptr = ptr;} blRawIterator(const blRawIterator<blDataType>& rawIterator) = default; ~blRawIterator(){} blRawIterator<blDataType>& operator=(const blRawIterator<blDataType>& rawIterator) = default; blRawIterator<blDataType>& operator=(blDataType* ptr){m_ptr = ptr;return (*this);} operator bool()const { if(m_ptr) return true; else return false; } bool operator==(const blRawIterator<blDataType>& rawIterator)const{return (m_ptr == rawIterator.getConstPtr());} bool operator!=(const blRawIterator<blDataType>& rawIterator)const{return (m_ptr != rawIterator.getConstPtr());} blRawIterator<blDataType>& operator+=(const ptrdiff_t& movement){m_ptr += movement;return (*this);} blRawIterator<blDataType>& operator-=(const ptrdiff_t& movement){m_ptr -= movement;return (*this);} blRawIterator<blDataType>& operator++(){++m_ptr;return (*this);} blRawIterator<blDataType>& operator--(){--m_ptr;return (*this);} blRawIterator<blDataType> operator++(ptrdiff_t){auto temp(*this);++m_ptr;return temp;} blRawIterator<blDataType> operator--(ptrdiff_t){auto temp(*this);--m_ptr;return temp;} blRawIterator<blDataType> operator+(const ptrdiff_t& movement){auto oldPtr = m_ptr;m_ptr+=movement;auto temp(*this);m_ptr = oldPtr;return temp;} blRawIterator<blDataType> operator-(const ptrdiff_t& movement){auto oldPtr = m_ptr;m_ptr-=movement;auto temp(*this);m_ptr = oldPtr;return temp;} ptrdiff_t operator-(const blRawIterator<blDataType>& rawIterator){return std::distance(rawIterator.getPtr(),this->getPtr());} blDataType& operator*(){return *m_ptr;} const blDataType& operator*()const{return *m_ptr;} blDataType* operator->(){return m_ptr;} blDataType* getPtr()const{return m_ptr;} const blDataType* getConstPtr()const{return m_ptr;} protected: blDataType* m_ptr; }; //------------------------------------------------------------------- 

2。

 //------------------------------------------------------------------- // Raw reverse iterator with random access //------------------------------------------------------------------- template<typename blDataType> class blRawReverseIterator : public blRawIterator<blDataType> { public: blRawReverseIterator(blDataType* ptr = nullptr):blRawIterator<blDataType>(ptr){} blRawReverseIterator(const blRawIterator<blDataType>& rawIterator){this->m_ptr = rawIterator.getPtr();} blRawReverseIterator(const blRawReverseIterator<blDataType>& rawReverseIterator) = default; ~blRawReverseIterator(){} blRawReverseIterator<blDataType>& operator=(const blRawReverseIterator<blDataType>& rawReverseIterator) = default; blRawReverseIterator<blDataType>& operator=(const blRawIterator<blDataType>& rawIterator){this->m_ptr = rawIterator.getPtr();return (*this);} blRawReverseIterator<blDataType>& operator=(blDataType* ptr){this->setPtr(ptr);return (*this);} blRawReverseIterator<blDataType>& operator+=(const ptrdiff_t& movement){this->m_ptr -= movement;return (*this);} blRawReverseIterator<blDataType>& operator-=(const ptrdiff_t& movement){this->m_ptr += movement;return (*this);} blRawReverseIterator<blDataType>& operator++(){--this->m_ptr;return (*this);} blRawReverseIterator<blDataType>& operator--(){++this->m_ptr;return (*this);} blRawReverseIterator<blDataType> operator++(ptrdiff_t){auto temp(*this);--this->m_ptr;return temp;} blRawReverseIterator<blDataType> operator--(ptrdiff_t){auto temp(*this);++this->m_ptr;return temp;} blRawReverseIterator<blDataType> operator+(const int& movement){auto oldPtr = this->m_ptr;this->m_ptr-=movement;auto temp(*this);this->m_ptr = oldPtr;return temp;} blRawReverseIterator<blDataType> operator-(const int& movement){auto oldPtr = this->m_ptr;this->m_ptr+=movement;auto temp(*this);this->m_ptr = oldPtr;return temp;} ptrdiff_t operator-(const blRawReverseIterator<blDataType>& rawReverseIterator){return std::distance(this->getPtr(),rawReverseIterator.getPtr());} blRawIterator<blDataType> base(){blRawIterator<blDataType> forwardIterator(this->m_ptr); ++forwardIterator; return forwardIterator;} }; //------------------------------------------------------------------- 

现在在您的自定义容器类中的某处:

 template<typename blDataType> class blCustomContainer { public: // The typedefs typedef blRawIterator<blDataType> iterator; typedef blRawIterator<const blDataType> const_iterator; typedef blRawReverseIterator<blDataType> reverse_iterator; typedef blRawReverseIterator<const blDataType> const_reverse_iterator; . . . public: // The begin/end functions iterator begin(){return iterator(&m_data[0]);} iterator end(){return iterator(&m_data[m_size]);} const_iterator cbegin(){return const_iterator(&m_data[0]);} const_iterator cend(){return const_iterator(&m_data[m_size]);} reverse_iterator rbegin(){return reverse_iterator(&m_data[m_size - 1]);} reverse_iterator rend(){return reverse_iterator(&m_data[-1]);} const_reverse_iterator crbegin(){return const_reverse_iterator(&m_data[m_size - 1]);} const_reverse_iterator crend(){return const_reverse_iterator(&m_data[-1]);} . . . }; 

祝你好运!!!

Boost有一些帮助:Boost.Iterator库。

更精确的说这个页面: boost :: iterator_adaptor 。

有趣的是教程示例 ,它显示了一个从头开始的自定义types的完整实现。

 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) {} // iterator convertible to const_iterator, not vice-versa 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(); } }; 

正如已经被引用的那样,主要的一点是使用一个模板实现并且typedef它。

我不知道Boost是否有任何帮助。

我最喜欢的模式很简单:采用一个模板参数,它等于value_type ,不pipe是否是const限定的。 如有必要,也是一个节点types。 那么,所有的事情都会落到实处。

只要记住参数化(template-ize)所有需要的东西,包括复制构造函数和operator==const的大部分语义会创build正确的行为。

 template< class ValueType, class NodeType > struct my_iterator : std::iterator< std::bidirectional_iterator_tag, T > { ValueType &operator*() { return cur->payload; } template< class VT2, class NT2 > friend bool operator== ( my_iterator const &lhs, my_iterator< VT2, NT2 > const &rhs ); // etc. private: NodeType *cur; friend class my_container; my_iterator( NodeType * ); // private constructor for begin, end }; typedef my_iterator< T, my_node< T > > iterator; typedef my_iterator< T const, my_node< T > const > const_iterator; 

他们经常忘记iterator必须转换为const_iterator而不是相反。 这是一个方法来做到这一点:

 template<class T, class Tag = void> class IntrusiveSlistIterator : public std::iterator<std::forward_iterator_tag, T> { typedef SlistNode<Tag> Node; Node* node_; public: IntrusiveSlistIterator(Node* node); T& operator*() const; T* operator->() const; IntrusiveSlistIterator& operator++(); IntrusiveSlistIterator operator++(int); friend bool operator==(IntrusiveSlistIterator a, IntrusiveSlistIterator b); friend bool operator!=(IntrusiveSlistIterator a, IntrusiveSlistIterator b); // one way conversion: iterator -> const_iterator operator IntrusiveSlistIterator<T const, Tag>() const; }; 

在上面的通知中, IntrusiveSlistIterator<T>如何转换为IntrusiveSlistIterator<T const> 。 如果T已经是const这个转换就不会被使用。

有很多很好的答案,但我有一个模板头,我使用的是相当简洁和易于使用。

要添加一个迭代器到你的类,只需要编写一个小类来表示迭代器的状态,其中7个小函数,其中2个是可选的:

 #include <iostream> #include <vector> #include "iterator_tpl.h" struct myClass { std::vector<float> vec; // Add some sane typedefs for STL compliance: STL_TYPEDEFS(float); struct it_state { int pos; inline void begin(const myClass* ref) { pos = 0; } inline void next(const myClass* ref) { ++pos; } inline void end(const myClass* ref) { pos = ref->vec.size(); } inline float& get(myClass* ref) { return ref->vec[pos]; } inline bool cmp(const it_state& s) const { return pos != s.pos; } // Optional to allow operator--() and reverse iterators: inline void prev(const myClass* ref) { --pos; } // Optional to allow `const_iterator`: inline const float& get(const myClass* ref) const { return ref->vec[pos]; } }; // Declare typedef ... iterator;, begin() and end() functions: SETUP_ITERATORS(myClass, float&, it_state); // Declare typedef ... reverse_iterator;, rbegin() and rend() functions: SETUP_REVERSE_ITERATORS(myClass, float&, it_state); }; 

那么你可以像使用STL迭代器那样使用它:

 int main() { myClass c1; c1.vec.push_back(1.0); c1.vec.push_back(2.0); c1.vec.push_back(3.0); std::cout << "iterator:" << std::endl; for (float& val : c1) { std::cout << val << " "; // 1.0 2.0 3.0 } std::cout << "reverse iterator:" << std::endl; for (auto it = c1.rbegin(); it != c1.rend(); ++it) { std::cout << *it << " "; // 3.0 2.0 1.0 } } 

我希望它有帮助。