这部分主要讲了常用迭代器用法的一些方面,分析STL中iterator、const_iterator、reverse_iterator和const_reverse_iterator的关系和一些转换,其内容比较少,简单。
Item26:Prefer iterator to const iterator, reverse_iterator, and const_reverse_iterator.
先看下四种迭代器之间的关系:
其中有些是可以通过隐式转换得到,而有些则要通过base()成员函数得到。在vector方法insert、erase中接受参数的都是iterator类型。尽量用iterator替代其他迭代器的原因主要如下:
1、insert和erase的一些版本要求iterator。
2、const_iterator不能隐式转换为iterator,手写转换不普遍且不高效。
3、
从reverse_iterator转换而来的iterator在转换之后可能需要相应的调整。
iterator和const_iterator之间的比较可能会带来一些麻烦,考虑下面代码:
typedef deque<int> IntDeque;
typedef IntDeque::iterator Iter;
typedef IntDeque::const_iterator ConstIter;
Iter i;
ConstIter ci;
...
if (i == ci) ...
比较过程会将iterator隐式转换成const_iterator,若有些实现将const_iterator的=操作符设为成员函数而不是非成员函数,那么这段代码就通不过,简单的解决方法是将i和ci位置互换。而在const和非const的随机访问迭代器之间进行算术运算时,则必须用static_case将iterator强制转换const_iterator。
Item 27. Use distance and advance to convert a container's const_iterators to iterators.
一般情况不能讲const_iterator用static_cast挥着其他方式转换为iterator,而reverse_iterator和const_reverse_iterator是类,更不能强制转换。他们之间的转换可以用distance和advance来实现,如下代码:
typedef deque<int> IntDeque;
typedef IntDeque::iterator Iter;
typedef IntDeque::const_iterator ConstIter;
IntDeque d;
ConstIter ci;
...
Iter i(d.begin());
advance(i, distance(i, ci));
上述代码有一个问题,distance参数是两个InputIterator类型的迭代器,而i和ci是两个不同类型迭代器,解决的方法是显式声明参数:
advance(i, distance<ConstIter>(i, ci));
上诉转换的效率可能是线性时间,这取决于distance的时间,对不同类型的iterator不同。
Item 28. Understand how to use a reverse_iterator's base iterator.
reverse_iterator通过base()可以得到对应的iterator,其具体的关系如下:

若要删除rt所指的元素,我们可以将其转换为iterator,然后删除,如下:
vector<int> v;
...
vecot<int>::reverse_iterator ri = find(v.rbegin(), v.rend(), 3);
v.erase(--ri.base());
但对于vector和string,有些实现的iterator采用内建指针,c/c++都规定不能直接修改函数返回的指针,那么我们可以调整reverst_iterator来避免修改base()返回的值:
v.erase((++ri).base());
Item 29. Consider istreambuf_iterators for character-by-character input.
考虑将一个文本文件拷贝到一个字符串中:
ifstream inputFile("interestingData.txt");
string fileData((istream_iterator<char>(inputFile)),
istream_iterator<char>());
这种方法无法将文件中的空格拷贝到字符串中,istream_iterator使用>>操作符来读取,默认忽略空格。一种方法是清除skipws标志:
inputFile.unset(ios::skipws);
但是这种方式的效率不是很高,operator>>是格式化输入,每次调用需要做大量的操作如建立和销毁sentry对象,检查流标志(skipws等),错误检查,异常处理等等。STL提供了一个高效的工具:istreambuf_iterators。像istream_iterator<char>对象使用operator>>来从输入流中读取单个字符,istreambuf_iterator<char>对象进入流的缓冲区并直接读取下一个字符,我们可以改变如下:
ifstream inputFile("interestingData.txt");
string fileData((istreambuf_iterator<char>(inputFile)),
istreambuf_iterator<char>());
istreambuf_iterator不忽略任何字符,不需要改变skipws标志,可以考虑把ostreambuf_iterator用于无格式字符的输出。
typedef deque<int> IntDeque;
typedef IntDeque::iterator Iter;
typedef IntDeque::const_iterator ConstIter;
Iter i;
ConstIter ci;
...
if (i == ci) ...
比较过程会将iterator隐式转换成const_iterator,若有些实现将const_iterator的=操作符设为成员函数而不是非成员函数,那么这段代码就通不过,简单的解决方法是将i和ci位置互换。而在const和非const的随机访问迭代器之间进行算术运算时,则必须用static_case将iterator强制转换const_iterator。
typedef deque<int> IntDeque;
typedef IntDeque::iterator Iter;
typedef IntDeque::const_iterator ConstIter;
IntDeque d;
ConstIter ci;
...
Iter i(d.begin());
advance(i, distance(i, ci));
上述代码有一个问题,distance参数是两个InputIterator类型的迭代器,而i和ci是两个不同类型迭代器,解决的方法是显式声明参数:
advance(i, distance<ConstIter>(i, ci));
上诉转换的效率可能是线性时间,这取决于distance的时间,对不同类型的iterator不同。

vector<int> v;
...
vecot<int>::reverse_iterator ri = find(v.rbegin(), v.rend(), 3);
v.erase(--ri.base());
但对于vector和string,有些实现的iterator采用内建指针,c/c++都规定不能直接修改函数返回的指针,那么我们可以调整reverst_iterator来避免修改base()返回的值:
v.erase((++ri).base());
ifstream inputFile("interestingData.txt");
string fileData((istream_iterator<char>(inputFile)),
istream_iterator<char>());
这种方法无法将文件中的空格拷贝到字符串中,istream_iterator使用>>操作符来读取,默认忽略空格。一种方法是清除skipws标志:
inputFile.unset(ios::skipws);
但是这种方式的效率不是很高,operator>>是格式化输入,每次调用需要做大量的操作如建立和销毁sentry对象,检查流标志(skipws等),错误检查,异常处理等等。STL提供了一个高效的工具:istreambuf_iterators。像istream_iterator<char>对象使用operator>>来从输入流中读取单个字符,istreambuf_iterator<char>对象进入流的缓冲区并直接读取下一个字符,我们可以改变如下:
ifstream inputFile("interestingData.txt");
string fileData((istreambuf_iterator<char>(inputFile)),
istreambuf_iterator<char>());
istreambuf_iterator不忽略任何字符,不需要改变skipws标志,可以考虑把ostreambuf_iterator用于无格式字符的输出。