How to customize C++ 's STL iterator
这篇文章主要介绍"C++的STL迭代器怎么自定义"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"C++的STL迭代器怎么自定义"文章能帮助大家解决问题。
C++ STL 迭代器
了解如何使用 C++ 标准模板库 (STL) 的容器的关键之一是了解迭代器的工作原理。lists 和maps等容器的行为不像数组,因此您不能使用for循环来遍历其中的元素。同样,因为这些容器不能随机访问,所以不能使用简单的整数索引。你可以使用迭代器来引用容器的元素。
STL 容器和算法可以很好地协同工作的原因是它们彼此一无所知 - Alex Stepanov
迭代器是类似指针的对象,它允许程序在不暴露底层表示的情况下顺序地遍历容器的元素。迭代器可以通过递增和递减它们从一个元素前进到下一个元素。每个容器类型都有一个与之关联的不同迭代器。例如,迭代器 forlist声明为:
std::list::iterator迭代器类别
迭代器分为几类,因为不同的算法需要使用不同的迭代器。例如,该std::copy()算法需要一个可以通过递增来推进的迭代器,而该 std::reverse()算法需要一个可以递减的迭代器。在 C++ 语言中,该标准定义了五个不同的类别。
输入迭代器
只读且只能读取一次。
例子: std::istream_iterator(istream& is)
输出迭代器
只写
例如:std::ostream_iterator out_it (std::cout,", ");
前向迭代器
收集输入+输出迭代器
示例:std::forward_list::iterator,std::unordered_map::iterator
双向迭代器
像前向迭代器,但也有 operator-
例子: std::list::iterator
随机访问迭代器
已重载operator[],指针运算
例子:std::vector::iterator。
你可以在此处获得有关这些的更多信息
迭代器特征
迭代器特征允许算法以统一的方式访问有关特定迭代器的信息,以避免在需要遍历不同样式的容器时为每个特定情况重新实现所有迭代器。例如,查找元素std::list是O(n)复杂性,而std::vector随机访问元素是O(1)复杂性(给定索引位置)。算法最好知道可以使用+=运算符(随机访问)或仅使用++运算符(转发)遍历容器,以选择更好的选择以降低计算的算法的复杂度。
迭代器特征如下:
difference_type:
表示迭代器距离的类型
迭代器的类型差异p2 - p1。
value_type:
迭代器指向的值的类型
pointer:
迭代器指向的指针值
通常 value_type*
reference:
迭代器指向的引用值
通常 value_type&
iterator category:
struct input_iterator_tag {};struct output_iterator_tag {};struct forward_iterator_tag : input_iterator_tag {};struct bidirectional_iterator_tag : forward_iterator_tag {};struct random_access_iterator_tag : bidirectional_iterator_tag {};
标识由迭代器建模的迭代器概念。
以下之一:
的定义iterator_traits看起来像:
// The basic version works for iterators with the member typetemplate struct iterator_traits{typedef typename Iterator::value_type value_type;typedef typename Iterator::difference_type difference_type;typedef typename Iterator::pointer pointer;typedef typename Iterator::reference reference;typedef typename Iterator::iterator_category iterator_category;};// A partial specialization takes care of pointer typestemplate struct iterator_traits{typedef T value_type;typedef ptrdiff_t difference_type;typedef T *pointer;typedef T &reference;typedef random_access_iterator_tag iterator_category;};// pointers to const typetemplate struct iterator_traits{typedef T value_type;typedef ptrdiff_t difference_type;typedef const T *pointer;typedef const T &reference;typedef random_access_iterator_tag iterator_category;};
有时,泛型算法需要知道其迭代器参数的值类型,即迭代器指向的类型。例如,要交换两个迭代器指向的值,就需要一个临时变量。
template void swap (Iterator a, Iterator b) { typename Iterator::value_type tmp = *a; *a = *b; *b = tmp;}
这些特征还通过利用iterator_category成员提供的有关基本迭代器类别的知识来提高算法的效率。算法可以使用这个"标签"来选择迭代器能够处理的最有效的实现,而不会影响处理各种迭代器类型的灵活性。
在下面的例子中,我们的目标是有一个单一的advance算法,可以根据迭代器类别自动执行正确的版本。
template void advance(InputIterator &i, Distance n, input_iterator_tag){for (; n > 0; --n)++i;}template void advance(BidirectionalIterator &i, Distance n bidirectional_iterator_tag){if (n 0; --n)++i;elsefor (; n
< 0; ++n)--i;}template void advance(RandomAccessIterator &i, Distance n, random_access_iterator_tag){i += n;}// Generic advance algorithm using compile-time dispatching based on function overloadingtemplate void advance(InputIterator i, Distance n){advance(i, n, typename iterator_traits::iterator_category());}编写自定义迭代器 迭代器特征将自动适用于定义适当成员类型的任何迭代器类。自定义迭代器应该支持以下指针: 如何检索该点的值 如何增加/减少迭代点 如何与其他迭代点进行比较 #include #include #include #include #include #include template class MyArray {private: ArrType *m_data; unsigned int m_size;public: class Iterator { public:// iterator_trait associated typestypedef Iterator itr_type;typedef ArrType value_type;typedef ArrType &reference;typedef ArrType *pointer;typedef std::bidirectional_iterator_tag iterator_category;typedef std::ptrdiff_t difference_type;Iterator(pointer ptr) : m_itr_ptr(ptr) {}itr_type operator++() { itr_type old_itr = *this; m_itr_ptr++; return old_itr;}itr_type operator++(int dummy) { m_itr_ptr++; return *this;}itr_type operator--() { itr_type old_itr = *this; m_itr_ptr--; return old_itr;}itr_type operator--(int dummy) { m_itr_ptr--; return *this;}reference operator*() const { return *m_itr_ptr; }pointer operator->() const { return m_itr_ptr; }bool operator==(const itr_type &rhs) { return m_itr_ptr == rhs.m_itr_ptr; }bool operator!= (const itr_type &rhs) { return m_itr_ptr != rhs.m_itr_ptr; } private:pointer m_itr_ptr; }; MyArray(unsigned int size) : m_size(size) { m_data = new ArrType[m_size]; } unsigned int size() const { return m_size; } ArrType &operator[](unsigned int idx) {if (idx >= m_size) throw std::runtime_error("Index out of range");return m_data[idx]; } Iterator begin() { return Iterator(m_data); } Iterator end() { return Iterator(m_data + m_size); }};int main(){ MyArray arr(3); arr[0] = 2.6; arr[1] = 5.2; arr[2] = 8.9; std::cout