STL实践与分析
--再谈迭代器【上】
引言:
另外三种迭代器类型:
1)插入迭代器:这类迭代器与容器绑定在一起,实现在容器中插入元素的功能。
2)iostream迭代器:这类迭代器可以与输入与输出流绑定在一起,用于迭代遍历所关联的IO流。
3)反向迭代器:这类迭代器实现向后遍历,而不是向前遍历,所有的容器都定义了自己的reverse_iterator类型,由rbegin和rend成员函数返回。
上述迭代器都在iterator头文件中定义。
一、插入迭代器
前面曾经提到的back_inserter函数是一种插入器,插入器适宜用迭代器适配器,其带有一个容器参数,并生成一个迭代器,用于在指定容器中插入元素。通过插入迭代器赋值时,迭代器将会插入一个新的元素。
C++提供了三种插入迭代器,其差别在于插入元素的位置不同:
1)back_inserter:创建使用push_back实现插入的迭代器。
2)front_inserter:使用push_front实现插入。
3)inserter:使用insert实现插入操作。出了所关联的容器外,inserter还带有第二个实参:指向插入起始位置的迭代器。
1、front_inserter需要使用push_front
front_inserter的操作类似于back_inserter:该函数创建一个迭代器,调用它所关联的基础容器的push_front成员函数代替赋值操作。
deque
iDeq;
front_inserter(iDeq) = 1; //OK
vector
iVec; front_inserter(iVec) = 1; //Error back_inserter(iVec) = 1; //OK
只有当容器提供 push_front操作时,才能使用front_inserter。在vector或其他没有push_front运算的容器上使用front_inserter,将产生错误。
2、inserter将产生在指定位置实现插入的迭代器
inserter适配器提供更普通的插入形式。这种适配器带有两个实参:所关联的容器和指示起始插入位置的迭代器。
list
::iterator it = find(iList.begin(),iList.end(),42);
/*
*在创建 inserter 时,应指明新元素在何处插入。
*inserter 函数总是在它的迭代器实参所标明的位置前面插入新元素。
*/
replace_copy(iVec.begin(),iVec.end(),inserter(iList,it),0,100);
3、inserter+容器的begin组合与 front_inserter的区别:
在使用front_inserter时,元素始终在容器的第一个元素前面插入。而使用inserter时,元素则在指定位置前面插入。
//理解下面输出的区别
list
ilst,ilst1,ilst2;
for (list
::size_type index = 0; index != 4; ++index) { ilst.push_front(index); } copy(ilst.begin(),ilst.end(),front_inserter(ilst1)); copy(ilst.begin(),ilst.end(),inserter(ilst2,ilst2.begin())); cout << "iList1: " << endl; for (list
::iterator iter = ilst1.begin(); iter != ilst1.end(); ++iter) { cout << *iter << '\t'; } cout << endl << "iList2: " << endl; for (list
::iterator iter = ilst2.begin(); iter != ilst2.end(); ++iter) { cout << *iter << '\t'; } cout << endl;
【小心地雷:】
front_inserter的使用将导致元素以相反的次序出现在目标对象中!
//P349 习题11.14 void printList(const list&iList) { for (list ::const_iterator iter = iList.begin();iter != iList.end(); ++iter) { cout << *iter << '\t'; } cout << endl; } int main() { list iList; list iList1,iList2,iList3; for (list ::size_type i = 0;i != 10; ++i) { iList.push_back(i); } cout << "iList: " << endl; printList(iList); replace_copy(iList.begin(),iList.end(),front_inserter(iList1),0,100); cout << "iList1: " << endl; printList(iList1); replace_copy(iList.begin(),iList.end(),inserter(iList2,iList2.begin()),0,100); cout << "iList2:" << endl; printList(iList2); replace_copy(iList.begin(),iList.end(),back_inserter(iList3),0,100); cout << "iList3:" << endl; printList(iList3); }
二、iostream迭代器
虽然iostream类型不是容器,但是标准库同样提供了iostream对象上使用的迭代器:istream_iterator用于读取输入流,而ostream_iterator用于写输出流。这些迭代器将它们所对应的流视为特定类型的元素序列。使用流迭代器时,可以用泛型算法从流对象中读取数据或写数据到流对象中。
| iostream迭代器的构造函数 |
|
|---|---|
| istream_iterator
|
创建从输入流strm中读取T类型对象的istream_iterator对象 |
| istream_iterator
|
istream_iterator对象的超出末端迭代器 |
| ostream_iterator
|
创建将T类型的对象写入到输出流strm的ostream_iterator对象 |
| ostream_iterator
|
创建将T类型的对象写入到输出流strm的ostream_iterator对象,再写入过程中使用delim作为元素的分隔符。delimit是以空字符结束的字符数组。 |
流迭代器只定义了最基本的迭代器操作:自增、解引用和赋值。此外,可比较两个istream迭代器是否相等(或不等)。而ostream迭代器则不提供比较运算
| istream_iterator的操作 |
|
|---|---|
| it1== it2 it1!= it2 |
比较两个istream_iterator对象是否相等/不等。迭代器必须读取的是相同的类型。如果两个迭代器都是end值,则它们相等。对于两个都不指向流结束符位置的迭代器,如果它们使用同一个输入流构造,则它们也相等。 |
| *it |
返回从流中读取的值 |
| it-> mem |
是(*it).mem的同义词,返回从流中读取的对象的mem成员 |
| ++it it++ |
通过使用元素类型提供的>>操作符从输入流中获取下一个元素值,使迭代器向前移动。通常,前缀版本使迭代器再流中向前移动,并返回对加1后的迭代器的引用。而后缀版本使迭代器在流中向前移动后,返回原值 |
1、流迭代器的定义
流迭代器都是类模板:任何已定义输入操作符(>>操作符)的类型都可以定义stream_iterator。类似地,任何已定义输出操作符(<<操作符)的类型也可定义ostream_iterator。
在创建流迭代器时,必须指定迭代器所读写的对象类型:
istream_iterator
cin_it(cin);
istream_iterator
end_of_stream; ofstream outfile; ostream_iterator
cout_it(outfile," ");