除了为每个容器定义的迭代器以外,标准库在头文件 iterator 中还定义了额外4种迭代器
插入迭代器 、 流迭代器 、 反向迭代器 、 移动迭代器
插入迭代器
基本介绍
插入器是一种迭代器适配器,接受一个容器,生成一个插入迭代器
vector<int> vi;
auto it = back_inserter(vi);
//back_inserter是插入器
//it是其生成的对应容器vi的插入器
对插入器赋值的时候,会自动向容器中添加元素
*it = 100; //将100插入vi尾部(插入类型由插入器决定)
cout<<vi.size()<<" "<<vi.front()<<endl;
//输出 1 100
插入迭代器定义了几种操作
*it = t; //在it指定位置插入值为t的元素,具体位置由插入器决定
/*--------*/
*it; //定义了这些操作,但不做任何事情,统一返回it
it++;
插入器的类型
back_inserter
总是向容器的末尾插入元素
vector<int> v1={1,2,3,4},v2;
auto back_it = back_inserter(v2);
copy(v1.begin(),v1.end(),back_it);
//v2中为 1 2 3 4
front_inserter
总是向容器的头插入元素
auto front_it = front_inserter(v2);
copy(v1.begin(),v1.end(),front_it);
//v2中为 4 3 2 1
//每次插入前都会更新插入位置确保总是在头部插入
//插入1后,容器的头就会重定位在1之前,所以2会插在1之前,以此类推
inserter
接受第二个参数:插入位置,第二个参数是一个指向给定容器的迭代器,元素将插在这个迭代器表示的元素前面
※ 插入的位置是静态的,创建时就确定,只会向那个位置插入元素
auto front_it = inserter(v2,v2.begin());
copy(v1.begin(),v1.end(),front_it);
//v2中为 1 2 3 4
由于插入位置是绑定不变的,所以插入位置的迭代器一旦失效就会造成异常
vector<int> v(10); //v有10个元素
auto it = inserter(v,v.end()); //v.end()在当前容器末尾,第10个元素后面
*it = 1; //ok
v.resize(5); //将容器大小缩小为5,原容器超过5的部位被删除
*it = 2; //触发异常,原来的位置已经被删掉
反向迭代器
位置和操作
- 位置
首 vec.begin()
尾后 vec.end()
———反———
首前 vec.rbegin()
尾 vec.rend()
操作
递增(++)、递减(- -)操作符的作用也反过来了
方向迭代器使用++从后向前遍历,使用- -从前往后遍历
反向迭代器需要递减运算符
forward_list 和 流迭代器 没有反向迭代器
反向迭代器与普通迭代器转换
- 用普通迭代器初始化反向迭代器
string str = "hello, world, hello, cpp.";
auto punct_it = find(str.begin(), str.end(), ','); //普通迭代器
string::reverse_iterator re_it(punct_it); //用普通迭代器punct_it初始化re_it
cout << *punct_it << " " << *re_it << endl;
//输出 , o
反向迭代器和普通迭代器并不指向同一个位置
反向迭代器返回普通迭代器
调用base成员函数
string str = "hello, world, hello, cpp.";
auto re_it = str.rend(); //反向迭代器 首前
auto it = re_it.base(); //获取普通迭代器,同样位置改变了
cout << *it << endl;
//输出 h
上面两个例子可以看出,普通迭代器和反向迭代器它们所指的元素是不同的
这样的设计思路是:普通迭代器与反向迭代器的目的是表示元素范围,而一个约定俗成的规定是用 左闭右开 区间来表示一个范围 ,把开始的方向称为左,结束的方向称为右