C++学习篇——C++ STL中迭代器介绍
2014-05-15 00:43
309 查看
迭代器(iterator)是连接容器和算法的纽带,为数据提供了抽象,使写算法的人不必关心各种数据结构的细节。迭代器提供了数据访问的标准模型——对象序列,使对容器更广泛的访问操作成为可能。
泛型编程的关键所在,就是如何找到一种通用的方法,来访问具有不同结构的各种容器中的每个元素,而这正是迭代器的功能。
迭代器是一种广义的指针,是指向序列元素指针概念的一种抽象。迭代器可以指向容器中的任意元素,还能遍历整个容器。
(序列)容器是数组的抽象,而迭代器则是指向数组指针的抽象。迭代器虽然是广义的指针,但是,迭代器并不是通用的指针。不同的容器可能需要不同的迭代器,实际上,在STL中,为每种容器都typedef了一个迭代器,名为iterator。例如,vector<T>的迭代器类型为<vector<T>::iterator(是一种随机访问迭代器)、list<T>的迭代器类型为list<T>::iterator(是一种双向迭代器)。
(1)特征与操作
l 迭代器的基本特征有:
n 解除——支持解除引用(dereference)操作,以便可以访问它引用的值。即,如果p是一个迭代器,则应该对*p和p->进行定义(似指针);
n 赋值——可将一个迭代器赋给另一个迭代器。即,如果p和q都是迭代器,则应该对表达式p=q进行定义;
n 比较——可将一个迭代器与另一个迭代器进行比较。即,如果p和q都是迭代器,则应该对表达式p==q和p!=q进行定义;
n 遍历——可以使用迭代器来遍历容器中的元素,这可以通过为迭代器p定义++p和p++操作来实现。
l 迭代器的操作有:
n 读——通过解除引用*来间接引用容器中的元素值,例如x = *p;
n 写——通过解除引用*来给容器中的元素赋值,例如*p = x;
n 访问——通过下标和指向引用容器中的元素及其成员,例如p[2]和p->m
n 迭代——利用增量和减量运算(++和--、+和-、+=和-=)在容器中遍历、漫游和跳跃,例如p++、--p、p+5、p-=8
n 比较——利用比较运算符(==、!=、<、>、<=、>=)来比较两个迭代器是否相等或谁大谁小,例如if(p < q)……;、wihle(p != c.end())……;
不同的泛型算法,对迭代器的要求也是不同的。例如,查找算法,只要求定义++操作符,以便迭代器能遍历整个容器,读取每一个元素的值来进行比较;但是,查找算法,并不需要修改数据,所以不要求写操作。排序算法则要求能随机访问,以便交换不相邻的元素;这需要对迭代器iter定义+操作,以便能够使用像iter + 12这样的表达式;另外,排序算法还要求可以读写数据。
(2)分类
根据迭代器所支持的操作不同,在STL中定义了如下5种迭代器:
l 输入迭代器(input iterator)——用于读取容器中的信息,但不一定能够修改它。
n 输入迭代器iter通过解除引用(即*iter),来读取容器中其所指向元素之值;
n 为了使输入迭代器能够访问容器中的所有元素的值,必须使其支持(前/后缀格式的)++ 操作符;
n 输入迭代器不能保证第二次遍历容器时,顺序不变;也不能保证其递增后,先前指向的值不变。即,基于输入迭代器的任何算法,都应该是单通(single-pass)的,不依赖于前一次遍历时的值,也不依赖于本次遍历中前面的值。
可见输入迭代器是一种单向的只读迭代器,可以递增但是不能递减,而且只能读不能写。适用于单通只读型算法。
l 输出迭代器(output iterator)——用于将信息传输给容器(修改容器中元素的值),但是不能读取。例如,显示器就是只能写不能读的设备,可用输出容器来表示它。也支持解除引用和++操作,也是单通的。所以,输出迭代器适用于单通只写型算法。
l 前向迭代器(forward iterator正向迭代器)——只能使用++操作符来单向遍历容器(不能用--)。与I/O迭代器一样,前向迭代器也支持解除引用与++操作。与I/O迭代器不同的是,前向迭代器是多通的(multi-pass)。即,它总是以同样的顺序来遍历容器,而且迭代器递增后,仍然可以通过解除保存的迭代器引用,来获得同样的值。另外,前向迭代器既可以是读写型的,也可以是只读的。
l 双向迭代器(bidirectional iterator)——可以用++和--操作符来双向遍历容器。其他与前向迭代器一样,也支持解除引用、也是多通的、也是可读写或只读的。
l 随机访问迭代器(random access iterator)——可直接访问容器中的任意一个元素的双向迭代器。
可见,这5种迭代器形成了一个层次结构:I/O迭代器(都可++遍历,但是前者只读/后者只写)最基本、前向迭代器可读写但只能++遍历、双向迭代器也可读写但能++/--双向遍历、随机迭代器除了能够双向遍历外还能够随机访问。
注意:各种迭代器的类型并不是确定的,而只是一种概念性的描述。不能用面向对象的语言来表达迭代器的种类,迭代器的种类只是一系列的要求,而不是一种类型(类)。在STL中,用概念(concept)一词来描述这一系列要求。因此,有输入迭代器概念和双向迭代器概念,但是却没有输入迭代器类型和双向迭代器类型。
(3)声明
迭代器类iterator和函数的声明都位于命名空间std中,可以在头文件<iterator>中找到:
namespace std { // 取自C++2003标准
// primitives:基础/原语
template<class Iterator> struct iterator_traits; // 迭代器特征
template<class T> struct iterator_traits<T*>; // 指针的专门化
template<class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&> struct iterator; // 迭代器
struct input_iterator_tag {}; // 迭代器标志(类别)
struct output_iterator_tag {};
struct forward_iterator_tag: public input_iterator_tag {};
struct bidirectional_iterator_tag: public forward_iterator_tag {};
struct random_access_iterator_tag: public bidirectional_iterator_tag {};
// iterator operations:迭代器操作
template <class InputIterator, class Distance> void advance(InputIterator& i, Distance n);
template <class InputIterator> typename iterator_traits<InputIterator>::difference_type distance(InputIterator first, InputIterator last);
// predefined iterators:预定义迭代器(及其比较运算符重载)
template <class Iterator> class reverse_iterator; // 反向迭代器
template <class Iterator> bool operator==(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> bool operator<(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> bool operator!=(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> bool operator>(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> bool operator>=(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> bool operator<=(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> typename reverse_iterator<Iterator>::difference_type operator- (const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> reverse_iterator<Iterator> operator+(typename reverse_iterator <Iterator>::difference_type n, const reverse_iterator<Iterator>& x);
// 插入器
template <class Container> class back_insert_iterator;
template <class Container> back_insert_iterator<Container> back_inserter(Container& x);
template <class Container> class front_insert_iterator;
template <class Container> front_insert_iterator<Container> front_inserter(Container& x);
template <class Container> class insert_iterator;
template <class Container, class Iterator>
insert_iterator<Container> inserter(Container& x, Iterator i);
// stream iterators:流迭代器
template <class T, class charT = char, class traits = char_traits<charT>, class Distance = ptrdiff_t> class istream_iterator;
template <class T, class charT, class traits, class Distance> bool operator==(const istream_iterator<T,charT,traits,Distance>& x, const istream_iterator<T, charT, traits, Distance>& y);
template <class T, class charT, class traits, class Distance> bool operator!=(const istream_iterator<T,charT,traits,Distance>& x, const istream_iterator<T, charT, traits, Distance>& y);
template <class T, class charT = char, class traits = char_traits<charT> > class ostream_iterator;
template<class charT, class traits = char_traits<charT> > class istreambuf_iterator;
template <class charT, class traits> bool operator==(const istreambuf_iterator<charT, traits>& a, const istreambuf_iterator<charT,traits>& b);
template <class charT, class traits> bool operator!=(const istreambuf_iterator<charT, traits>& a, const istreambuf_iterator<charT,traits>& b);
template <class charT, class traits = char_traits<charT> > class ostreambuf_iterator;
}
(4)预定义迭代器
STL有一个使用方便的预定义迭代器集合,其中包括正向迭代器、反向迭代器、插入器和流迭代器。
l 正向迭代器:
template<class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&> struct iterator;
在所有的标准容器类中,都定义了返回iterator对象的成员函数begin()和end()。例如
通过在程序中调用它们,就可以得到正向迭代器 iterator的对象,从而能够正向遍历容器。例如:(c为任意标准容器对象,op为某一函数对象)
for_each(c.begin(), c.end(), op);
l 反向迭代器:
template <class Iterator> class reverse_iterator;
在标准容器中调用rbegin()和rend(),就可以得到反向迭代器 reverse_iterator的对象,从而可反向遍历容器。例如:
运行结果 为将此代码反序输出。先输出最后一行
l 插入器
如果需要输出或复制元素到容器,又不想覆盖容器中原有的内容,还要避免溢出,这就需要插入器来帮忙。STL提供了三种插入器,分别对应于后插、前插和中插:
template <class Container> class back_insert_iterator; // 在尾部插入
template <class Container> back_insert_iterator<Container> back_inserter(Container& x);
template <class Container> class front_insert_iterator; // 在头部插入
template <class Container> front_insert_iterator<Container> front_inserter(Container& x);
template <class Container> class insert_iterator; // 在中间插入
template <class Container, class Iterator>
insert_iterator<Container> inserter(Container& x, Iterator i);
例如:
运行结果为:
23 19 17 13 11 7 5 3 1
23 19 17 13 11 7 5 3 1
1 3 5 7 11 13 17 19 23
1 3 5 7 11 13 17 19 23
1 3 5 7 11 13 17 19 23
1 3 5 1 3 5 7 7 11 13 17 19 23
1 3 5 1 3 5 7 7 11 13 17 19 23
1 3 5 1 3 5 7 7 11 13 17 19 23
l 流迭代器
一般I/O是通过C++的流库或C的I/O函数完成的,也可以通过GUI的对话框等来进行I/O操作。这些I/O接口的基本目标,是读取各种类型的单个值。
为了使I/O能够以序列的方式呈现,将流I/O融入容器和算法的通用框架之中,STL还提供了4个流迭代器的模版类:
n istream_iterator——用于从输入流读取
n ostream_iterator——用于向输出流写入
n istreambuf_iterator——用于从输入流缓冲区读取
n ostreambuf_iterator——用于向输出流缓冲区写入
从输入流读取的操作,由对输入流迭代器is的间接引用*is的赋值来进行,在每两次输入之间,必须进行一次增量操作,为下一次输入做好准备。类似地,写出到输出流的操作,由对输出流迭代器os的间接引用*os的赋值来进行,在每两次输出之间,也必须进行一次增量操作,为下一次输出做好准备。
例如:
运行结果如下:
580
78
56
i1 = 78, i2 = 56
又例如:
(5)指针与迭代器
既然迭代器是广义的指针,那么指针本身是不是迭代器呢?其实,指针满足所有迭代器的要求,所以,指针就是一种迭代器。
迭代器是泛型算法的接口,而指针是迭代器。所以,各种STL算法,也可以使用指针,来对非标准容器(如数组)进行操作。即,利用指针做迭代器,可以将STL算法用于常规数组。
例如排序函数sort:
sort(Ran first, Ran last); // Ran表示随机访问迭代器
对容器c为:
sort(c.begin(), c.end());
对数组a可以改为:(const int SIZE = 100; float a[SIZE];)
sort(a, a + SIZE);
又例如复制函数copy:
copy(In first, In last, Out res); // In和Out分别表示输入和输出迭代器
对容器c<int>可为:(ostream_iterator<int> out_iter(cout);)
copy(c.begin(), c.end(), out_iter);
对数组a可以改为:(const int SIZE = 100; float a[SIZE];)
copy(a, a + SIZE, c.begin());
泛型编程的关键所在,就是如何找到一种通用的方法,来访问具有不同结构的各种容器中的每个元素,而这正是迭代器的功能。
迭代器是一种广义的指针,是指向序列元素指针概念的一种抽象。迭代器可以指向容器中的任意元素,还能遍历整个容器。
(序列)容器是数组的抽象,而迭代器则是指向数组指针的抽象。迭代器虽然是广义的指针,但是,迭代器并不是通用的指针。不同的容器可能需要不同的迭代器,实际上,在STL中,为每种容器都typedef了一个迭代器,名为iterator。例如,vector<T>的迭代器类型为<vector<T>::iterator(是一种随机访问迭代器)、list<T>的迭代器类型为list<T>::iterator(是一种双向迭代器)。
(1)特征与操作
l 迭代器的基本特征有:
n 解除——支持解除引用(dereference)操作,以便可以访问它引用的值。即,如果p是一个迭代器,则应该对*p和p->进行定义(似指针);
n 赋值——可将一个迭代器赋给另一个迭代器。即,如果p和q都是迭代器,则应该对表达式p=q进行定义;
n 比较——可将一个迭代器与另一个迭代器进行比较。即,如果p和q都是迭代器,则应该对表达式p==q和p!=q进行定义;
n 遍历——可以使用迭代器来遍历容器中的元素,这可以通过为迭代器p定义++p和p++操作来实现。
l 迭代器的操作有:
n 读——通过解除引用*来间接引用容器中的元素值,例如x = *p;
n 写——通过解除引用*来给容器中的元素赋值,例如*p = x;
n 访问——通过下标和指向引用容器中的元素及其成员,例如p[2]和p->m
n 迭代——利用增量和减量运算(++和--、+和-、+=和-=)在容器中遍历、漫游和跳跃,例如p++、--p、p+5、p-=8
n 比较——利用比较运算符(==、!=、<、>、<=、>=)来比较两个迭代器是否相等或谁大谁小,例如if(p < q)……;、wihle(p != c.end())……;
不同的泛型算法,对迭代器的要求也是不同的。例如,查找算法,只要求定义++操作符,以便迭代器能遍历整个容器,读取每一个元素的值来进行比较;但是,查找算法,并不需要修改数据,所以不要求写操作。排序算法则要求能随机访问,以便交换不相邻的元素;这需要对迭代器iter定义+操作,以便能够使用像iter + 12这样的表达式;另外,排序算法还要求可以读写数据。
(2)分类
根据迭代器所支持的操作不同,在STL中定义了如下5种迭代器:
l 输入迭代器(input iterator)——用于读取容器中的信息,但不一定能够修改它。
n 输入迭代器iter通过解除引用(即*iter),来读取容器中其所指向元素之值;
n 为了使输入迭代器能够访问容器中的所有元素的值,必须使其支持(前/后缀格式的)++ 操作符;
n 输入迭代器不能保证第二次遍历容器时,顺序不变;也不能保证其递增后,先前指向的值不变。即,基于输入迭代器的任何算法,都应该是单通(single-pass)的,不依赖于前一次遍历时的值,也不依赖于本次遍历中前面的值。
可见输入迭代器是一种单向的只读迭代器,可以递增但是不能递减,而且只能读不能写。适用于单通只读型算法。
l 输出迭代器(output iterator)——用于将信息传输给容器(修改容器中元素的值),但是不能读取。例如,显示器就是只能写不能读的设备,可用输出容器来表示它。也支持解除引用和++操作,也是单通的。所以,输出迭代器适用于单通只写型算法。
l 前向迭代器(forward iterator正向迭代器)——只能使用++操作符来单向遍历容器(不能用--)。与I/O迭代器一样,前向迭代器也支持解除引用与++操作。与I/O迭代器不同的是,前向迭代器是多通的(multi-pass)。即,它总是以同样的顺序来遍历容器,而且迭代器递增后,仍然可以通过解除保存的迭代器引用,来获得同样的值。另外,前向迭代器既可以是读写型的,也可以是只读的。
l 双向迭代器(bidirectional iterator)——可以用++和--操作符来双向遍历容器。其他与前向迭代器一样,也支持解除引用、也是多通的、也是可读写或只读的。
l 随机访问迭代器(random access iterator)——可直接访问容器中的任意一个元素的双向迭代器。
可见,这5种迭代器形成了一个层次结构:I/O迭代器(都可++遍历,但是前者只读/后者只写)最基本、前向迭代器可读写但只能++遍历、双向迭代器也可读写但能++/--双向遍历、随机迭代器除了能够双向遍历外还能够随机访问。
注意:各种迭代器的类型并不是确定的,而只是一种概念性的描述。不能用面向对象的语言来表达迭代器的种类,迭代器的种类只是一系列的要求,而不是一种类型(类)。在STL中,用概念(concept)一词来描述这一系列要求。因此,有输入迭代器概念和双向迭代器概念,但是却没有输入迭代器类型和双向迭代器类型。
(3)声明
迭代器类iterator和函数的声明都位于命名空间std中,可以在头文件<iterator>中找到:
namespace std { // 取自C++2003标准
// primitives:基础/原语
template<class Iterator> struct iterator_traits; // 迭代器特征
template<class T> struct iterator_traits<T*>; // 指针的专门化
template<class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&> struct iterator; // 迭代器
struct input_iterator_tag {}; // 迭代器标志(类别)
struct output_iterator_tag {};
struct forward_iterator_tag: public input_iterator_tag {};
struct bidirectional_iterator_tag: public forward_iterator_tag {};
struct random_access_iterator_tag: public bidirectional_iterator_tag {};
// iterator operations:迭代器操作
template <class InputIterator, class Distance> void advance(InputIterator& i, Distance n);
template <class InputIterator> typename iterator_traits<InputIterator>::difference_type distance(InputIterator first, InputIterator last);
// predefined iterators:预定义迭代器(及其比较运算符重载)
template <class Iterator> class reverse_iterator; // 反向迭代器
template <class Iterator> bool operator==(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> bool operator<(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> bool operator!=(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> bool operator>(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> bool operator>=(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> bool operator<=(const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> typename reverse_iterator<Iterator>::difference_type operator- (const reverse_iterator<Iterator>& x, const reverse_iterator<Iterator>& y);
template <class Iterator> reverse_iterator<Iterator> operator+(typename reverse_iterator <Iterator>::difference_type n, const reverse_iterator<Iterator>& x);
// 插入器
template <class Container> class back_insert_iterator;
template <class Container> back_insert_iterator<Container> back_inserter(Container& x);
template <class Container> class front_insert_iterator;
template <class Container> front_insert_iterator<Container> front_inserter(Container& x);
template <class Container> class insert_iterator;
template <class Container, class Iterator>
insert_iterator<Container> inserter(Container& x, Iterator i);
// stream iterators:流迭代器
template <class T, class charT = char, class traits = char_traits<charT>, class Distance = ptrdiff_t> class istream_iterator;
template <class T, class charT, class traits, class Distance> bool operator==(const istream_iterator<T,charT,traits,Distance>& x, const istream_iterator<T, charT, traits, Distance>& y);
template <class T, class charT, class traits, class Distance> bool operator!=(const istream_iterator<T,charT,traits,Distance>& x, const istream_iterator<T, charT, traits, Distance>& y);
template <class T, class charT = char, class traits = char_traits<charT> > class ostream_iterator;
template<class charT, class traits = char_traits<charT> > class istreambuf_iterator;
template <class charT, class traits> bool operator==(const istreambuf_iterator<charT, traits>& a, const istreambuf_iterator<charT,traits>& b);
template <class charT, class traits> bool operator!=(const istreambuf_iterator<charT, traits>& a, const istreambuf_iterator<charT,traits>& b);
template <class charT, class traits = char_traits<charT> > class ostreambuf_iterator;
}
(4)预定义迭代器
STL有一个使用方便的预定义迭代器集合,其中包括正向迭代器、反向迭代器、插入器和流迭代器。
l 正向迭代器:
template<class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&> struct iterator;
在所有的标准容器类中,都定义了返回iterator对象的成员函数begin()和end()。例如
namespace std { template <class T, class Allocator = allocator<T> > class vector { public: …… // iterators:迭代器 iterator begin(); // 指向首元素 const_iterator begin() const; iterator end(); // 指向尾元素后的一个位置 const_iterator end() const; reverse_iterator rbegin(); // 指向反向序列的首元素 const_reverse_iterator rbegin() const; reverse_iterator rend(); // 指向反向序列尾元素后的一个位置 const_reverse_iterator rend() const; …… } }
通过在程序中调用它们,就可以得到正向迭代器 iterator的对象,从而能够正向遍历容器。例如:(c为任意标准容器对象,op为某一函数对象)
for_each(c.begin(), c.end(), op);
l 反向迭代器:
template <class Iterator> class reverse_iterator;
在标准容器中调用rbegin()和rend(),就可以得到反向迭代器 reverse_iterator的对象,从而可反向遍历容器。例如:
// Revers.cpp #include <fstream> #include <iostream> #include <string> #include <vector> using namespace std; int main() { ifstream in("Revers.cpp"); if(!in) { cout << " Open file Revers.cpp error ! " << endl; return 1; } string line; vector<string> lines; while(getline(in, line)) lines.push_back(line); for(vector<string>::reverse_iterator r = lines.rbegin(); r != lines.rend(); r++) cout << *r << endl; }
运行结果 为将此代码反序输出。先输出最后一行
l 插入器
如果需要输出或复制元素到容器,又不想覆盖容器中原有的内容,还要避免溢出,这就需要插入器来帮忙。STL提供了三种插入器,分别对应于后插、前插和中插:
template <class Container> class back_insert_iterator; // 在尾部插入
template <class Container> back_insert_iterator<Container> back_inserter(Container& x);
template <class Container> class front_insert_iterator; // 在头部插入
template <class Container> front_insert_iterator<Container> front_inserter(Container& x);
template <class Container> class insert_iterator; // 在中间插入
template <class Container, class Iterator>
insert_iterator<Container> inserter(Container& x, Iterator i);
例如:
// Insert.cpp #include <iostream> #include <vector> #include <deque> #include <list> #include <iterator> using namespace std; int a[] = { 1, 3, 5, 7, 11, 13, 17, 19, 23 }; // 质数序列 template<class Cont> void frontInsertion(Cont& ci) { // 前插 copy(a, a + sizeof(a)/sizeof(Cont::value_type), front_inserter(ci)); // 插入a // 插入空格 copy(ci.begin(), ci.end(), ostream_iterator<typename Cont::value_type>(cout, " ")); cout << endl; } template<class Cont> void backInsertion(Cont& ci) { // 后插 copy(a, a + sizeof(a)/sizeof(Cont::value_type), back_inserter(ci)); // 插入a // 插入空格 copy(ci.begin(), ci.end(), ostream_iterator<typename Cont::value_type>(cout, " ")); cout << endl; } template<class Cont> void midInsertion(Cont& ci) { // 中插 typename Cont::iterator it = ci.begin(); ++it; ++it; ++it; // 迭代器指向第4个元素 copy(a, a + sizeof(a)/(sizeof(Cont::value_type) * 2), inserter(ci, it)); // 插入9/2=4个数 // 插入空格 copy(ci.begin(), ci.end(), ostream_iterator<typename Cont::value_type>(cout, " ")); cout << endl; } int main() { deque<int> di; list<int> li; vector<int> vi; frontInsertion(di); frontInsertion(li); // frontInsertion(vi); // 对向量不能使用前插 di.clear(); li.clear(); backInsertion(vi); backInsertion(di); backInsertion(li); midInsertion(vi); midInsertion(di); midInsertion(li); }
运行结果为:
23 19 17 13 11 7 5 3 1
23 19 17 13 11 7 5 3 1
1 3 5 7 11 13 17 19 23
1 3 5 7 11 13 17 19 23
1 3 5 7 11 13 17 19 23
1 3 5 1 3 5 7 7 11 13 17 19 23
1 3 5 1 3 5 7 7 11 13 17 19 23
1 3 5 1 3 5 7 7 11 13 17 19 23
l 流迭代器
一般I/O是通过C++的流库或C的I/O函数完成的,也可以通过GUI的对话框等来进行I/O操作。这些I/O接口的基本目标,是读取各种类型的单个值。
为了使I/O能够以序列的方式呈现,将流I/O融入容器和算法的通用框架之中,STL还提供了4个流迭代器的模版类:
n istream_iterator——用于从输入流读取
n ostream_iterator——用于向输出流写入
n istreambuf_iterator——用于从输入流缓冲区读取
n ostreambuf_iterator——用于向输出流缓冲区写入
从输入流读取的操作,由对输入流迭代器is的间接引用*is的赋值来进行,在每两次输入之间,必须进行一次增量操作,为下一次输入做好准备。类似地,写出到输出流的操作,由对输出流迭代器os的间接引用*os的赋值来进行,在每两次输出之间,也必须进行一次增量操作,为下一次输出做好准备。
例如:
// Stream.cpp #include<iostream> #include<iterator> using namespace std; int main() { ostream_iterator<int> os(cout); // 将int通过os输出到cout *os = 5; // 输出5(用cout << 5;) os++; // 准备好下一次的输出 *os = 80; istream_iterator<int> is(cin); // 通过is从cin读入int int i1 = *is; // 输入到i1 is++; // 准备好下一次的输入 int i2 = *is; // 输入到i2 cout << "i1 = " << i1 << ", i2 = " << i2 << endl; }
运行结果如下:
580
78
56
i1 = 78, i2 = 56
又例如:
// StreamIt.cpp #include <fstream> #include <iostream> #include <iterator> #include <string> #include <vector> using namespace std; int main() { ifstream in("StreamIt.cpp"); istream_iterator<string> begin(in), end; ostream_iterator<string> out(cout, " "); vector<string> vs; copy(begin, end, back_inserter(vs)); copy(vs.begin(), vs.end(), out); *out++ = vs[0]; *out++ = "That's all, folks!"; }
(5)指针与迭代器
既然迭代器是广义的指针,那么指针本身是不是迭代器呢?其实,指针满足所有迭代器的要求,所以,指针就是一种迭代器。
迭代器是泛型算法的接口,而指针是迭代器。所以,各种STL算法,也可以使用指针,来对非标准容器(如数组)进行操作。即,利用指针做迭代器,可以将STL算法用于常规数组。
例如排序函数sort:
sort(Ran first, Ran last); // Ran表示随机访问迭代器
对容器c为:
sort(c.begin(), c.end());
对数组a可以改为:(const int SIZE = 100; float a[SIZE];)
sort(a, a + SIZE);
又例如复制函数copy:
copy(In first, In last, Out res); // In和Out分别表示输入和输出迭代器
对容器c<int>可为:(ostream_iterator<int> out_iter(cout);)
copy(c.begin(), c.end(), out_iter);
对数组a可以改为:(const int SIZE = 100; float a[SIZE];)
copy(a, a + SIZE, c.begin());
相关文章推荐
- C++学习篇——C++ STL中迭代器介绍
- C++学习篇——C++ STL中迭代器介绍
- C++学习篇——C++ STL中迭代器介绍
- C++ STL中迭代器介绍
- C++ STL中迭代器介绍
- C++ 中Traits技术 (5) —— 关于STL中对迭代器封装的类型介绍
- C++ 有关于STL中 迭代器的基本介绍 20180321day11
- C++学习篇——C++ STL中迭代器介绍(收集)
- c++ _STL基本容器总结介绍
- C++ STL中哈希表 hash_map介绍
- C++中防止STL中迭代器失效——map/set等关联容器——vector/list/deque等序列容器—如何防止迭代器失效—即erase()的使用
- C++ iostream 迭代器 STL
- [Z]C++ STL中哈希表 hash_map介绍
- C++——STL所有算法介绍
- C++ STL中哈希表 hash_map介绍
- 【C++ STL学习之八】逆向迭代器reverse_iterator
- 关于C++ STL key_comp value_comp的问题 能否介绍下这两个东西?以set为例子好了,谢谢
- C++ STL概要介绍
- C++ STL中哈希表 hash_map介绍
- (转)C++ STL的各种实现版本介绍