C++ Primer第十章③
C++ Primer
泛型算法
再探迭代器
除了前面介绍的标准库容器迭代器外,C++还在头文件iterator中定义了额外的集中迭代器:
- 插入迭代器:绑定到容器上,可用来向容器中插入元素(前面提到过的)
- 流迭代器:绑定到输入输出流上,可用来遍历所关联的IO流
- 反向迭代器:跟普通的迭代器方向相反(forward_list没有这个,你懂得)
- 移动迭代器:移动而不是拷贝元素(以后再详细介绍)
插入迭代器
//有三种,back_inserter, front_inserter, inserter
vector<int> vec;
auto it = back_inserter(vec);
*it = 0; //{0}
auto is = front_inserter(vec);
*is = -1; {-1, 0}头插
list<int> lst = {1, 2, 3};
list<int> lst1;
copy(list.cbegin(), lst.cend(), inserter(lst1, lst1.begin()) ); //lst1拷贝了lst
iostream迭代器
虽然iostream不是容器,但标准库还是定义了这些类型对象的迭代器。istream_iterator读取输入流,ostream_iterator向一个输出流写数据。这些迭代器将它们对应的流当作一个特定类型的元素序列来处理,通过使用流迭代器,我们可以使用泛型算法从流对象读取数据以及向其写入数据
下面是一个用istream_iterator从标准输入读取数据,存入一个vector的例子:
istream_iterator<int> in_iter(cin); //从cin读取int
istream_iterator<int> eof; //空的istream_iterator当作istream尾后迭代器
while(in_iter != eof)
{
vec.push_back(*in_iter++);
}
这样写看起来和以前差别不大,我们来个牛逼的写法:
istream_iterator<int> in_iter(cin), eof;
vector<int> vec(in_iter, eof);
这两行代码和上面的程序完全等价:我们用一对元素范围的迭代器来构造vec,这个构造函数通过in_iter从cin中读取数据,直到遇到文件尾或者遇到不是int的数据为止,从流中读取的数据用于构造vec
再来个酷炫的,输入数据求和:
istream_iterator<int> in(cin), eof;
cout << accumulate(in, eof, 0) << endl; //从标准输入中读取数值求和输出
标准库不保证迭代器立即从流中读取数据,只保证在第一次解引用迭代器之前读数据已经完成。
ostream_iterator操作
输出流迭代器操作 | 含义 |
---|---|
ostream_iterator<T> out(os); | out将类型为T的值写到输出流os中 |
ostream_iterator<T> out(os, d); | out将类型为T的值写到输出流os中,每个值后面都输出一个d。d指向一个空字符结尾的字符数组 |
我们可以用ostream_iterator来输出值的序列:
ostream_iterator<int> out_iter(cout, " ");
for(auto e : vec)
{
*out_iter++ = e; //实际将元素e写到cout
}
cout << endl;
其实我们还可以这样写(最好还是用上面的,保持一致嘛):
for(auto e : vec)
{
out_iter = e; //*和++运算符实际上不对ostream_iterator对象做任何事,可以忽略
}
使用流迭代器处理类类型
我们来用IO迭代器重写一下让我们赚了2000块的书店程序:
istream_iterator<Sales_item> item_iter(cin), eof;
ostream_iterator<Sales_item> out_iter(cout, "\n");
//读取第一笔交易,并准备读取下一条
Sales_item sum = *item_iter++;
while(item_oter != eof)
{
if(item_iter->isbn() == sum.isbn())
{
sum += *item_iter++;
}
else
{
out_iter = sum; //输出
sum = *item_iter++; //读取下一条
}
}
out_iter = sum; //打印最后一组
反向迭代器
这个图已经非常清楚了,再来个例子,逆序打印vec中的元素:
vector<int> vec = {1, 2, 3};
for(auto r_iter = vec.crbegin(); r_iter != vec.crend(); ++r_iter)
{
cout << *r_iter << endl;
}
反向迭代器使用的时候要注意两点,一个是元素范围,尤其是边界到底是开区间还是闭区间;还有要注意的就是++和--时的前进方向