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

新手上路,请多包涵

我有一个自定义容器类,我想为其编写 iteratorconst_iterator 类。

我以前从未这样做过,也没有找到合适的方法。关于迭代器创建的指导方针是什么,我应该注意什么?

我还想避免代码重复(我觉得 const_iteratoriterator 共享很多东西;一个应该继承另一个吗?)。

脚注:我很确定 Boost 可以缓解这种情况,但由于许多愚蠢的原因,我不能在这里使用它。

原文由 ereOn 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 895
2 个回答
  • 选择适合您容器的迭代器类型:输入、输出、转发等。
  • 使用标准库中的基迭代器类。例如 std::iteratorrandom_access_iterator_tag 。这些基类定义了 STL 所需的所有类型定义并做其他工作。
  • 为避免代码重复,迭代器类应该是一个模板类,并由“值类型”、“指针类型”、“引用类型”或所有这些参数化(取决于实现)。例如:
   // 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_type 类型定义:它们是非常量和常量迭代器的类型。

另请参阅: 标准库参考

编辑: std::iterator 自 C++17 起已弃用。请参阅 此处 的相关讨论。

原文由 Andrey 发布,翻译遵循 CC BY-SA 4.0 许可协议

我很想知道这是多么 _正确_,但似乎可以作为内部数据存储的滚动您自己的迭代器

template<typename T>
struct iterator_type
{
    using self_type             = iterator_type;
    using iterator_category     = std::random_access_iterator_tag;
    using difference_type       = std::ptrdiff_t;
    using value_type            = std::remove_cv_t<T>;
    using pointer               = T*;
    using reference             = T&;

    iterator_type( pointer ptr ) noexcept
        : _ptr{ ptr }
    {}

    reference operator*() noexcept { return *_ptr; }
    pointer operator->() noexcept { return _ptr; }

    self_type operator++() noexcept { ++_ptr; return *this; }
    self_type operator++(int) noexcept { self_type tmp = *this; ++_ptr; return tmp; }

    self_type operator--() noexcept { --_ptr; return *this; }
    self_type operator--(int) noexcept { self_type tmp = *this; --_ptr; return tmp; }

    bool operator==( const self_type &other ) const noexcept { return _ptr == other._ptr; }
    bool operator!=( const self_type &other ) const noexcept { return _ptr != other._ptr; }

private:
    pointer _ptr;
};

template<typename T>
using const_iterator_type = iterator_type<std::add_const_t<T>>;

然后我只是将这些添加到我的课程中,并且似乎按预期工作。

 template<typename T>
class Container
{
public:
    using iterator               = iterator_type<T>;
    using const_iterator         = const_iterator_type<T>;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

...

    iterator begin() { return _begin; }
    iterator end() { return _begin + _size; }

    const_iterator cbegin() const { return _begin; }
    const_iterator cend() const { return _begin + _size; }

    reverse_iterator rbegin() { return reverse_iterator(_begin + _size); }
    reverse_iterator rend() { return reverse_iterator(_begin); }

    const_reverse_iterator crbegin() const { return const_reverse_iterator(_begin + _size); }
    const_reverse_iterator crend() const { return const_reverse_iterator(_begin); }

private:
    T*         _begin;
    size_t     _size;
    size_t     _capacity;
};

the only thing is that to make it with the std::cbegin() , std::rcbegin() , std::cend() and std::rcend() functions I have to extend the std 命名空间:

 namespace std
{
    template<typename T>
    typename Container<T>::const_iterator cbegin( Container<T> &c ) { return c.cbegin(); }

    template<typename T>
    typename Container<T>::const_iterator cend( Container<T> &c ) { return c.cend(); }

    template<typename T>
    typename Container<T>::const_reverse_iterator crbegin( Container<T> &c ) { return c.crbegin(); }

    template<typename T>
    typename Container<T>::const_reverse_iterator crend( Container<T> &c ) { return c.crend(); }
}

原文由 Treebeard 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题