除普通的容器迭代器外,标准库还定义了一些迭代器,包含在头文件<iterator>中:
1、插入迭代器
作用:插入迭代器接受一个容器生成一个迭代器,能实现向给定容器添加元素。
对插入迭代器赋值会在插入迭代器所指位置创建赋值的元素的拷贝。
插入迭代器的作用是将赋值改为插入,将泛型算法中的修改变为写入。
以下函数会返回一个插入迭代器:
back_inserter(c) : 接受一个容器的引用c,返回一个与该容器绑定的插入迭代器,该插入迭代器将赋值的拷贝插入到队尾(执行的是push_back)。
inserter(c, p) : 接受一个容器的引用c和迭代器p,返回一个与该容器绑定的插入迭代器,该插入迭代器将赋值的拷贝插入到迭代器所指位置之前(执行的是insert)
front_inserter(c):接受一个容器的引用c,返回一个与该容器绑定的插入迭代器,该插入迭代器将赋值的拷贝插入到队首(执行的是push_front)
插入迭代器支持的操作:
it = t | 在it指定位置插入值t。 |
*it, ++it, it++ | 不做任何操作,只返回it,存在是为了对齐其他迭代器的使用格式 |
插入迭代器的常用形式:*it++ = t; 相当于普通迭代器it2的操作: it2 = c.insert(it2, val); ++it2;
2、流迭代器
标准库定义了可以用于IO类型对象的迭代器。
ostream_iterator :向一个输出流写数据
istream_iterator:读取输入流
流迭代器的作用是,我们可以用泛型算法从流对象读取数据以及向其写入数据,流迭代器必须指定迭代器从流中读取的数据的类型。
输入流迭代器支持的操作:
istream_iterator<T> in(is); | 创建一个接受T类型值的 绑定到输入流 is 的流迭代器 |
istream_iterator<T> eof; | 默认初始化流迭代器,可以作为一个尾后迭代器 |
in1 == in2; in1 != in2; | 当in1与in2绑定到相同的输入流时,或二者都是尾后迭代器时,二者相等,否则不等 |
*in | 返回从流中读取的值 |
in->mem | 访问从流中读取的值的成员 |
++in,in++ | 使用元素类型所对应的>>运算符读取下一个值,前置返回当前的读取,后置返回前一个读取。 |
以下是一个用istream_iterator从标准输入读取数据,存入一个vector的例子:
istream_iterator<int> int_it(cin); // 创建一个读取int类型数据的输入流迭代器,并绑定到cin流
istream_iterator<int> int_eof;// 默认初始化,不绑定到输入流,表示创建了一个输入流的尾后迭代器。
while(in_iter != eof) vec.push_back(*in_iter++); // 获取从流读取的前一个值。
对于一个绑定到流的迭代器,一旦其关联的流遇到文件尾或遇到IO错误,迭代器的值就与尾后迭代器相等,即,遇到文件尾或IO错误等于对流的遍历结束。
输入流迭代器在泛型算法中的应用:
- 将输入的内容直接存入容器中:
copy(in_iter, eof, back_inserter(vec));// 将输入内容按空格分隔存入vector<int>类型的容器vec中。
- 将输入累加:
accumulate(in_iter, eof, 0); // 累加输入内容初值为0
istream_iterator直到使用迭代器时才真正从流中读取。
输出流迭代器:
ostream_iterator支持的操作:
ostream_iterator<T> out(os); | 创建一个流迭代器out,绑定到输出流os,out输出的内容类型为T |
ostream_iterator<T> out(os, d); | out将类型为T的值写到输出流中,每次输出之后打印一个d, d是一个C风格字符串。 |
out = val; | 调用<<运算符将val存入out绑定的ostream中,相当于os << val; 但规定val的类型为T |
*out, ++out, out++ | 不做任何事,只返回out,只为了对齐迭代器格式。 |
输出流迭代器应用实例:
ostream_iterator<string> out(cout, " ");
vector<string> vec{"abc", "def", "ghi"};
auto iter = vec.begin();
while(iter != vec.end()){
*out++ = *iter++; // 相当于:cout << *iter++;
}
3、反向迭代器(forward_list没有反向迭代器)
反向迭代器reverse_iterator就是从尾元素开始向首元素反向移动的迭代器。
可以通过rbegin()\rend()\crbegin()\crend()获取反向迭代器。反向迭代器的rend()是容器首元素之前的一个元素,即首前的位置。对反向迭代器递增得到的是容器中它之前的一个元素。反向迭代器要求容器迭代器支持自减,因此需要双向迭代器权限的容器才支持反向迭代器。
4、移动迭代器
通过调用标准库的make_move_iterator函数,将普通迭代器转换为一个移动迭代器,它接受一个普通迭代器,返回一个移动迭代器。
移动迭代器应用实例:
uninitialized_copy(make_move_iterator(vec.begin()), make_move_iterator(vec.end()), first);// 将vec的元素移动到first指向的原始内存空间。
建议:尽量少地使用移动功能。
迭代器等级
迭代器按可提供的操作分为5个类别:
1、输入迭代器: 只可读入,不能写入,只能递增
可读取序列中的元素
支持的操作:
==、!= ,++,*,->
只能用于顺序访问。
2、输出迭代器: 只写不读,只能递增
支持的操作:
++、*
只能向一个输出迭代器赋值一次,因此输出迭代器是单向的。输出流迭代器是一种输出迭代器。在泛型函数中用作目标迭代器的迭代器 被要求是输出迭代器,比如copy(b1, e1, b2); b2必须至少是一个输出迭代器。
3、前向迭代器 :可以读写元素
只能在序列中沿一个方向移动(通常是只能++不能--),forward_list上的迭代器是一个典型的前向迭代器。
前向迭代器支持所有输入和输出迭代器的操作,且可以多次读写同一个元素。
4、双向迭代器 :可以正向/反向读写序列中的元素。
除了支持所有前向迭代器的操作外,双向迭代器还支持前置和后置递减运算符(--)。
reverse要求双向迭代器。
除了forward_list之外,对于其他容器,标准库都提供符合双向迭代器要求的迭代器。
5、随机访问迭代器
支持双向迭代器的所有操作,且支持随机访问(提供在常量时间内访问序列中任意元素的能力)。
额外支持的操作:
<, <=, >, >= |
iter+n, iter+=n, iter-n, iter-=n |
iter1-iter2 |
iter[n] |
array、deque、string、vector的迭代器都是随机访问迭代器。
sort要求随机访问迭代器
泛型算法的参数规范:
alg(beg, end, other args); // beg,end是操作序列的迭代器范围, other args是关于算法所需的其他参数
alg(beg, end, dest, other args);
alg(beg, end, beg2, other args);
alg(beg, end, beg2, end2, other args);
以及泛型算法后缀:_if(满足条件则执行操作), _copy(将序列复制到目的序列)