C++ 标准库迭代器概念与分类

一. 前言

        C++ 标准库提供了许多容器,如 list,vector,deque 等,同时标准库还提供了一种方便程序员遍历访问 STL 的手段,例如我们可以使用下标的方式来访问 vector 容器,但是对于 list 容器,显然用下标来遍历访问不太合理。

vector<int> vec = {1,2,3,4,5,6,7};
for(decltype(vec.size()) i = 0;i < vec.size();++i)
{
    cout << vec[i] << " ";
}

如果使用迭代器的方式遍历 vector,可以改成如下的方式。

vector<int> vec = {1,2,3,4,5,6,7};
for(auto it = vec.begin();it != vec.end();++it)
{
    cout << *it << " ";
}

如果你想访问 list 容器,也可以使用类似于上面的方式访问。

 

二. 迭代器的概念

        迭代器在行为上是一种类似于指针的对象,它表示容器中的某一个位置,迭代器紧密依赖于容器,是由容器提供的,我们可以通过解引用的方式获得容器中该位置的元素值。

 

三. 迭代器的分类

        迭代器可以分为输入迭代器输出迭代器前向迭代器双向迭代器随机访问迭代器。迭代器分类的依据是:迭代器的移动特性以及在这个迭代器上所能做的操作。对于 vector 容器,其迭代器如果想往前或者往后移动到若干个元素前后的位置,只需要对迭代器加减要移动的元素个数值就可以了,对于 list,由于容器本身不是线性存储的,因此迭代器的移动就不能加上一个数字来移动了,只能通过 ++ 和 -- 移动 list 迭代器,所以我们称 vector<type>::iterator 是随机访问迭代器,list<type>::iterator 是双向迭代器。

 

(一)输入迭代器

表达式含义
iter1 == iter2判断两个迭代器是否相等
iter1 != iter2 判断两个迭代器是否不相等
++iter迭代器向前移动,前置版本
iter++迭代器向前移动,后置版本
*iter读取迭代器指向的容器元素
iter->member等价于(*it).member
TYPE(iter)复制迭代器

        一个输入迭代器必须支持比较两个迭代器是否相等用于推进迭代器位置向前移动的前置和后置递增运算,注意我们这里所说的向前移动是指从 begin-> end 这个方向;用于读取元素的解引用运算符,并且解引用只能出现在赋值运算符右侧;箭头运算符,等价于(*it).member。输入迭代器只能用于单遍扫描算法,例如算法 find 和 accumulate 要求的迭代器类型就是输入迭代器类型。

        istream_iterator 就是一种输入迭代器。

 

(二)输出迭代器

表达式含义
*iter = val将val写入迭代器所指的位置
++iter迭代器向前移动,前置版本
iter++迭代器向前移动,后置版本
TYPE(iter)复制迭代器

输出迭代器可以看做是输入迭代器的补集,只写而不读元素。输出迭代器需要支持推进迭代器位置向前移动的前置和后置版本的递增运算;解引用运算符,并且只出现在赋值运算符的左侧,我们只能向一个输出迭代器赋值一次。

        ostream_iterator 和 inserter 就是输出迭代器。

 

(三)前向迭代器

表达式含义
*iter读取迭代器指向的容器元素
iter->member等价于(*it).member
++iter迭代器向前移动,前置版本
iter++迭代器向前移动,后置版本
iter1 == iter2判断两个迭代器是否相等
iter1 != iter2判断两个迭代器是否不相等
TYPE()创建迭代器
TYPE(iter)复制迭代器
iter1 = iter2使用迭代器iter2给迭代器iter1赋值

        前向迭代器可以读写元素,这类迭代器只能在序列中沿一个方向移动,前向迭代器支持所有输入和输出迭代器的操作,而且可以多次读写同一个元素。

        forward_list 容器中定义的的迭代器就是前向迭代器。

 

(四)双向迭代器

表达式含义
--iter迭代器往后移动,前置版本
iter--迭代器往后移动,后置版本

        双向迭代器可以正反方向读写序列中的元素,除了支持前向迭代器的所有操作以外,还提供了递减运算符,代表让迭代器往后移动。

        list,set,multiset,map 和 multimap 容器中定义的迭代器属于双向迭代器类型。

 

(五)随机访问迭代器

表达式含义
iter[n]访问索引位置为n的元素
iter+=n向前移动n个元素的位置
iter-=n向后回退n个元素的位置
iter+n返回iter后第n个元素的位置
iter-n返回iter前第n个元素的位置
iter1-iter2返回iter1和iter2之间的距离
iter1<iter2判断iter1是否在iter2之前
iter1>iter2判断iter1是否在iter2之后
iter1<=iter2判断iter1是否不在iter2之后
iter1>=iter2判断iter1是否不在iter2之前

        随机访问迭代器提供在常量时间内访问序列中任意元素的能力,此类迭代器不仅支持双向迭代器的所有功能,还提供用于比较两个迭代器相对位置的关系运算符(<,<=,>,>=);迭代器和一个整数值的加减运算,计算结果是迭代器在序列中前进或者后退给定整数个元素后的位置;两个迭代器间的减法运算,得到两个迭代器的距离;下标运算符

        array,vector,deque,string 容器定义的迭代器就是随机访问迭代器类型。

 

四. 使用程序判断迭代器的类型

        那么怎么通过程序来验证容器迭代器的类型呢?只要使用萃取技术即可。

#include <iostream>
#include <array>
#include <vector>
#include <map>
#include <list>
#include <iterator>

using namespace std;

void _display_category(input_iterator_tag)
{
    cout << "input_iterator_tag" << endl;
}

void _display_category(forward_iterator_tag)
{
    cout << "forward_iterator_tag" << endl;
}

void _display_category(bidirectional_iterator_tag)
{
    cout << "bidirectional_iterator_tag" << endl;
}

void _display_category(random_access_iterator_tag)
{
    cout << "random_access_iterator_tag" << endl;
}

template <typename Type>
void display_category(Type type)
{
    cout << "--------------begin--------------" << endl;
    typename iterator_traits<Type>::iterator_category cateGory;
    _display_category(cateGory);
    cout << "" << typeid(type).name() << endl;
    cout << "--------------end--------------" << endl;
}

int main()
{
    display_category(array<int, 10>::iterator());
    display_category(list<int>::iterator());
    display_category(map<int, int>::iterator());
    display_category(vector<int>::iterator());

    return 0;
}

        使用 list<int>::iterator() 或者 map<int,int>::iterator() 都可以生成一个类型对象,传递进模板的 type 进去,再使用萃取技术就可以获取类型。

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

椛茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值