STL实践与分析
--再谈迭代器【下】
三、反向迭代器【续:习题】
//P355 习题11.19 int main() { vector<int> iVec; for (vector<int>::size_type index = 0; index != 10; ++index) { iVec.push_back(index); } for (vector<int>::reverse_iterator r_iter = iVec.rbegin(); r_iter != iVec.rend(); ++r_iter) { cout << *r_iter << endl; } }
//习题 11.20 int main() { vector<int> iVec; for (vector<int>::size_type index = 0; index != 10; ++index) { iVec.push_back(index); } for (vector<int>::iterator iter = iVec.end()-1;iter >= iVec.begin(); --iter) { cout << *iter << endl; } }
//习题 11.21 int main() { int ia[] = {0,1,2,3,4,5,6,0,7,8,9,0,10}; vector<int> iVec(ia,ia + sizeof(ia)/sizeof(*ia)); vector<int>::reverse_iterator r_iter = find(iVec.rbegin(),iVec.rend(),0); if (r_iter != iVec.rend()) { cout << "element after the last 0 : " << *(-- r_iter) << endl; } else { cout << "Not found!" << endl; } }
//习题11.22 int main() { int ia[] = {0,1,2,3,4,5,6,0,7,8}; vector<int> iVec(ia,ia + sizeof(ia)/sizeof(*ia)); list<int> iList; vector<int>::reverse_iterator rbeg = iVec.rbegin(),rend; for (int i = 0; i != 3; ++i) ++ rbeg; rend = rbeg; for (int i = 0; i != 5; ++i) ++rend; copy(rbeg,rend,back_inserter(iList)); for (list<int>::iterator iter = iList.begin(); iter != iList.end(); ++iter) { cout << *iter << endl; } }
四、const迭代器
算法要求用于指定范围的两个迭代器必须具有全然一样的类型。比方我们曾将使用的find_first_of算法:
find_first_of(it, roster1.end(),roster2.begin(), roster2.end())
该函数调用的输入范围由it和调用roster1.end()返回的迭代器指定。算法要求用于指定范围的两个迭代器必须具有全然一样的类型。roster1.end()返回的迭代器依赖于roster1的类型。假设该容器是const对象,则返回的迭代器是const_iterator类型;否则,就是普通的iterator类型。在这个程序中,roster1不是 const对象,因而end返回的仅仅是一个普通的迭代器。
假设我们将it定义为const_iterator,那么find_first_of的调用将无法编译。用来指定范围的两个迭代器的类型不同样。it是 const_iterator类型的对象,而rotser1.end()返回的则是一个iterator对象。
五、五种迭代器
能够依据算法要求它的迭代器的提供什么类型的操作,对算法分类:
迭代器分类 | |
---|---|
输入迭代器 | 读,不能写:仅仅支持自增运算 |
输出迭代器 | 写,不能读:仅仅支持自增运算 |
前向迭代器 | 读和写:仅仅支持自增运算 |
双向迭代器 | 读和写:支持自增、自减运算 |
随机訪问迭代器 | 读和写:支持完整的迭代器算术运算 |
1、输入迭代器
可用于读取容器中的元素,可是不保证能够支持容器的写入操作。输入迭代器必须至少提供下列操作:
1)相等和不等操作符(==,!=),比較两个迭代器。
2)前置和后置的自增运算(++),使迭代器向前递进指向下一个元素。
3)用于读取元素的解引用操作符(*),此操作符仅仅能出如今赋值运算的右操作数上。
4)箭头操作符(->),这是(*it).member的同义语,也就是说,对迭代器进行解引用来获取其所关联的对象的成员。
输入迭代器仅仅能顺序使用;一旦输入迭代器自增了,就无法再用它检查之前的元素。要求在这个层次上提供支持的泛型算法包含find和 accumulate。标准库istream_iterator类型输入迭代器。
2、输出迭代器
能够视为与输入迭代器功能互补的迭代器;输入迭代器可用于向容器写入元素,但不保证能支持读取容器的内容。输入迭代器要求:
1)前置和后置的自增运算(++),使迭代器向前递进指向下一个元素。
2)解引用操作符(*),引操作符仅仅能出如今赋值运算的左操作数上。给解引用的输出迭代器赋值,将对该迭代器所指向的元素做写入操作。
输出迭代器能够要求每个迭代器的值必须正好写入一次。使用输出迭代器时,对于指定的迭代器值应该使用一次*运算,并且仅仅能用一次。输出迭代器一般用作算法的第三个实參,标记起始写入的位置。比如,copy算法使用一个输出迭代器作为它的第三个实參,将输入范围内的元素拷贝到输出迭代器指定的目标位置。标准库ostream_iterator类型输出迭代器
3、前向迭代器
用于读写指定的容器。这类迭代器仅仅会以一个方向遍历序列。前向迭代器支持输入迭代器和输出迭代器提供的全部操作,除此之外,还支持对同一个元素的多次读写。须要前向迭代器的泛型算法包含replace。
4、双向迭代器
从两个方向读写容器。出了提供前向迭代器的全部操作,还支持前置和后置的自减运算(--)。须要使用双向迭代器的泛型算法包含reverse。全部标准库容器提供的迭代器都至少达到双向迭代器的要求。
5、随机訪问迭代器
提供在常量时间内訪问容器任何位置的功能。不仅支持双向迭代器的全部功能,还支持以下的操作:
1)关系操作符<、<=、>和>=,比較两个迭代器的相对位置。
2)迭代器与整型数值n之间的加法和减法操作符+、+=、-和 -=,结果是迭代器在容器中向前(或退回)n个元素。
3)两个迭代器之间的减法操作符(--),得到两个迭代器间的距离。
4)下标操作符iter[n],这是*(iter+ n) 的同义词。
须要随机訪问迭代器的泛型算法包含sort算法。vector、deque和string迭代器是随机訪问迭代器,用作訪问内置数组元素的指针也是随机訪问迭代器。
除了输出迭代器,其它类别的迭代器形成了一个层次结构:须要低级类别迭代器的地方,可使用随意一种更高级的迭代器。
【总结】
map、set和 list类型提供双向迭代器,而string、vector和 deque容器上定义的迭代器都是随机訪问迭代器都是随机訪问迭代器,用作訪问内置数组元素的指针也是随机訪问迭代器。istream_iterator是输入迭代器,而ostream_iterator则是输出迭代器。
【关键概念:关联容器与算法】
虽然map和 set类型提供双向迭代器,但关联容器仅仅能使用算法的一个子集。问题在于:关联容器的键是const对象。因此,关联容器不能使用不论什么写序列元素的算法。仅仅能使用与关联容器绑在一起的迭代器来提供用于读操作的实參。
在处理算法时,最好将关联容器上的迭代器视为支持自减运算的输入迭代器,而不是完整的双向迭代器。
【重点理解】
C++标准为全部泛型和算术算法的每个迭代器形參指定了范围最小的迭代器种类。比如:find至少须要一个输入迭代器。replace函数至少须要一对前向迭代器。replace_copy函数的头两个迭代器必须至少是前向迭代器,第三个參数代表输出目标,必须至少是输出迭代器。
对于每个形參,迭代器必须保证最低功能。将支持更少功能的迭代器传递给函数是错误的;而传递更强功能的迭代器则没问题。
向算法传递无效的迭代器类别所引起的错误,无法保证会在编译时被捕获到。
//P358 习题11.26(d) vector<int> iVec1,iVec2; //... //解释下列语句错误的原因,以及编译器是否能检測出这类错误? sort(iVec1.begin(),iVec2.end());