c++ - 如何实现 STL 风格的迭代器并避免常见的陷阱?

标签 c++ iterator const-iterator

我创建了一个集合,我想为其提供一个 STL 风格的随机访问迭代器。我正在四处寻找迭代器的示例实现,但没有找到。我知道 []* 运算符需要 const 重载。迭代器要成为“STL 风格”的要求是什么?还有哪些其他需要避免的陷阱(如果有的话)?

附加上下文:这是一个库,我不想引入任何对它的依赖,除非我真的需要。我编写了自己的集合,以便能够使用相同的编译器提供 C++03 和 C++11 之间的二进制兼容性(因此没有可能会破坏的 STL)。

最佳答案

https://cplusplus.com/reference/iterator/有一个方便的图表,详细说明了 C++11 标准第 24.2.2 节的规范。基本上,迭代器具有描述有效操作的标签,并且标签具有层次结构。下面纯粹是象征性的,这些类实际上并不存在。

iterator {
    iterator(const iterator&);
    ~iterator();
    iterator& operator=(const iterator&);
    iterator& operator++(); //prefix increment
    reference operator*() const;
    friend void swap(iterator& lhs, iterator& rhs); //C++11 I think
};

input_iterator : public virtual iterator {
    iterator operator++(int); //postfix increment
    value_type operator*() const;
    pointer operator->() const;
    friend bool operator==(const iterator&, const iterator&);
    friend bool operator!=(const iterator&, const iterator&); 
};
//once an input iterator has been dereferenced, it is 
//undefined to dereference one before that.

output_iterator : public virtual iterator {
    reference operator*() const;
    iterator operator++(int); //postfix increment
};
//dereferences may only be on the left side of an assignment
//once an output iterator has been dereferenced, it is 
//undefined to dereference one before that.

forward_iterator : input_iterator, output_iterator {
    forward_iterator();
};
//multiple passes allowed

bidirectional_iterator : forward_iterator {
    iterator& operator--(); //prefix decrement
    iterator operator--(int); //postfix decrement
};

random_access_iterator : bidirectional_iterator {
    friend bool operator<(const iterator&, const iterator&);
    friend bool operator>(const iterator&, const iterator&);
    friend bool operator<=(const iterator&, const iterator&);
    friend bool operator>=(const iterator&, const iterator&);

    iterator& operator+=(size_type);
    friend iterator operator+(const iterator&, size_type);
    friend iterator operator+(size_type, const iterator&);
    iterator& operator-=(size_type);  
    friend iterator operator-(const iterator&, size_type);
    friend difference_type operator-(iterator, iterator);

    reference operator[](size_type) const;
};

contiguous_iterator : random_access_iterator { //C++17
}; //elements are stored contiguously in memory.

您可以专精 std::iterator_traits<youriterator> , 或将相同的 typedefs 放入迭代器本身,或从 std::iterator 继承(有这些 typedef)。我更喜欢第二个选项,以避免更改 std 中的内容。命名空间,并且为了可读性,但大多数人继承自 std::iterator .

struct std::iterator_traits<youriterator> {        
    typedef ???? difference_type; //almost always ptrdiff_t
    typedef ???? value_type; //almost always T
    typedef ???? reference; //almost always T& or const T&
    typedef ???? pointer; //almost always T* or const T*
    typedef ???? iterator_category;  //usually std::forward_iterator_tag or similar
};

注意 iterator_category 应该是 std::input_iterator_tag 之一, std::output_iterator_tag , std::forward_iterator_tag , std::bidirectional_iterator_tag , 或 std::random_access_iterator_tag ,取决于您的迭代器满足哪些要求。根据您的迭代器,您可以选择专门化 std::next , std::prev , std::advance , 和 std::distance也可以,但这很少需要。在极为罕见的情况下,您可能希望特化 std::beginstd::end .

您的容器可能还应该有一个 const_iterator ,它是常量数据的(可能是可变的)迭代器,类似于您的 iterator除非它应该可以从 iterator 隐式构造并且用户应该无法修改数据。它的内部指针通常是指向非常量数据的指针,并且有 iterator继承自 const_iterator以尽量减少代码重复。

我在 Writing your own STL Container 的帖子有更完整的容器/迭代器原型(prototype)。

关于c++ - 如何实现 STL 风格的迭代器并避免常见的陷阱?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8054273/

相关文章:

java - 在 Java 中遍历 ArrayList 的 ArrayList

C++ |重载运算符 << |标准:: map

c++ - 返回 const 和非常量包装对象

c++ - 如何从 C++ 中的 Windows 注册表中获取计算机制造商和型号?

c++ - 如何在果酱工具的 UI 中添加按钮?

c++ - map 上的迭代器永远不会 atteins map.end()

c++ - 存储和管理 std::list::iterator

c++ - 将返回的迭代器转换为 const

c++ - "Defaulted" move 构造函数和赋值 - 奇怪的行为

c++ - Windows 64位共享dll Tesseract?