【问题标题】:How to provide STL like iterators for my collection class? [duplicate]如何为我的集合类提供类似 STL 的迭代器? [复制]
【发布时间】:2011-05-06 17:58:38
【问题描述】:

可能重复:
How to correctly implement custom iterators and const_iterators ?

我真的很想为我拥有的实体集合类提供一个类似 STL 的迭代器。作为奖励,如果迭代器可以轻松地用于我得到的其他集合类,我会喜欢它。问题是我曾经尝试过 STL,但对我来说太复杂了。关于如何做到这一点的任何建议?它不需要像 STL 迭代器那么复杂,但如果我可以说 MyCollection::iterator it = o_MyCollection.begin() 等等,我会喜欢它。 :)

作为第二个问题,如果我要将这个迭代器传递给像for_each 这样的常用算法,那么这个迭代器的基本要求是什么?

【问题讨论】:

  • 你试过搜索吗?这个线程上有一些很好的指示-stackoverflow.com/questions/148540/c-creating-my-own-iterators
  • 为什么投反对票?我明白为什么它可能会因为重复而被关闭,但这似乎不是一个值得被否决的问题。
  • 为什么不让你的集合类成为 STL 集合的包装器呢?然后,您可以简单地公开您需要的任何运算符。

标签: c++ templates iterator


【解决方案1】:

假设您的集合是一个由整数索引的列表,我在自定义 STL 集合中使用的这个迭代器类可能会对您有所帮助。它使用curiously recurring template pattern。它没有经过 100% 测试,但可以在我的代码中使用。

// common_safe_iterator is instantiated to produce both const_iterator and
// iterator types. It called "safe" because it is not necessarily invalidated
// by changes to the collection size, and it calls at() on the target
// collection, which is supposed to throw an exception if the index is
// out-of-range, instead of calling [] which does not.
template<class base>
class common_safe_iterator : public base {
protected:
    // base must contain the following 5 typedefs
    typedef typename base::reference reference;
    typedef typename base::pointer pointer;
    typedef typename base::vector_t vector_t;
    typedef typename base::const_iterator_t const_iterator_t;
    typedef typename base::iterator_t iterator_t;
    vector_t* _vec;
    size_type _pos;
public:
    typedef common_safe_iterator<base> self;
    friend const_iterator_t;

    common_safe_iterator(vector_t* vec, size_type pos) : _vec(vec), _pos(pos) { }
    common_safe_iterator(const iterator_t& copy) : _vec(copy._vec), _pos(copy._pos) { }

    reference operator*() const { return _vec->at(_pos); }
    pointer operator->() const { return &_vec->at(_pos); }

    self& operator++() // prefix ++
        { ++_pos; return *this; }
    self& operator--() // prefix --
        { --_pos; return *this; }
    self& operator+=(int amt) 
        { _pos += amt; return *this; }
    bool operator==(const self& x) const
        { return (x._vec == _vec) && (x._pos == _pos); }
    int operator-(const self& base) const
        { assert(base._vec == _vec); return _pos - base._pos; }
    // Returns true if the iterator can be dereferenced
    bool is_valid() const
        { return _vec != NULL && _pos < _vec->size(); }

    /////////////////////////////////////////////////////////
    // Operators that are defined in terms of other operators

    self operator++(int) // postfix ++
    {
        self tmp = *this; // copy ourselves
        ++*this;
        return tmp;
    }
    self operator--(int) // postfix --
    {
        self tmp = *this; // copy ourselves
        --*this;
        return tmp;
    }
    self& operator-=(int amt)
    {
        return *this += -amt;
    }
    bool operator!=(const self& x) const
    {
        return !(*this == x);
    }
    bool operator>(const self& x) const
    {
        return *this - x > 0;
    }
    bool operator>=(const self& x) const
    {
        return *this - x >= 0;
    }
    bool operator<(const self& x) const
    {
        return *this - x < 0;
    }
    bool operator<=(const self& x) const
    {
        return *this - x <= 0;
    }
    self operator+(int amt) const
    {
        self tmp = *this;
        return tmp += amt;
    }
    self operator-(int amt) const
    {
        self tmp = *this;
        return tmp -= amt;
    }
    reference operator[](int index) const
    {
        self tmp = *this;
        tmp += index;
        return *tmp;
    }
};

STL 希望您同时提供“const_iterator”和非常量“iterator”类。为此,编写两个基类,每个基类有 5 个 typedef。我的集合类名为 mini_vector_t,所以我使用以下基类:

/// iterator and const_iterator differ only in these typedefs.
/// const_iterator_base is the base class of const_iterator, while
/// iterator_base is the base class of iterator; both iterator and
/// const_iterator are typedefs of common_safe_iterator.
struct iterator_base;
struct const_iterator_base
{
    typedef const typename mini_vector_t::value_type& reference;
    typedef const typename mini_vector_t::value_type* pointer;
    typedef const mini_vector_t vector_t;
    typedef common_safe_iterator<const_iterator_base> const_iterator_t;
    typedef common_safe_iterator<iterator_base> iterator_t;
};
struct iterator_base
{
    typedef typename mini_vector_t::value_type& reference;
    typedef typename mini_vector_t::value_type* pointer;
    typedef mini_vector_t vector_t;
    typedef common_safe_iterator<const_iterator_base> const_iterator_t;
    typedef common_safe_iterator<iterator_base> iterator_t;
};

最后,你的集合必须包含 const_iterator 和 iterator 的 typedef:

typedef common_safe_iterator<const_iterator_base> const_iterator;
typedef common_safe_iterator<iterator_base> iterator;

如果您的集合包装了一个数组,那么一个更简单的替代方法是使用 T* 作为您的迭代器类型,并使用 const T* 作为您的 const_iterator 类型:

typedef T* iterator;
typedef const T* const_iterator;

请记住,STL 被设计成指针本身就是迭代器。

我认为你应该做一些额外的事情来声明你的迭代器是“随机访问”的,但我不知道是什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-12
    • 1970-01-01
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    • 1970-01-01
    相关资源
    最近更新 更多