C++精华(STL)学习笔记之迭代器

来源:互联网 发布:js 小数转整数 编辑:程序博客网 时间:2024/05/17 08:56

<utility.h>utility中只有模版类pair,和一些与之相关联得模版操作符,该模版类用来将两个对象合并为一个对象,当你想要一个函数返回两个值得时就比较方便了。

其中模版函数make_pair可以在必要时产生一个pair对象,该函数在检测参数时忽略掉所有CONST属性,所以不能依赖他产生包含一个或多个常量成员对象得pair对象。

测试文件:

 #include "iostream"
#include "assert.h"
#include "utility"
using namespace std;

class Int
{
public:
 Int(int v):val(v){}
 Int(){val=0;}
 bool operator==(Int x)const{return (val==x.val);}//仅重载==AND<就可以了,其他的库会帮我们完成
 bool operator<(Int x) const{return (val<x.val);} //重载函数
private:
 int val;
};

typedef pair<int ,char>pair_ic;
pair_ic p0;

typedef pair<Int,char>pair_id;
pair_id d0;

int main()
{
 pair_ic p1=p0,p2(3,'a');
 assert(p1.first==0);
 assert(p1.second==0);
 assert(p2.first==3);
 assert(p2.second=='a');
 assert(p2==make_pair((pair_ic::first_type)3,(pair_ic::second_type)'a'));
 assert(p2<make_pair((pair_ic::first_type)4,(pair_ic::second_type)'a'));
 assert(p2<make_pair((pair_ic::first_type)3,(pair_ic::second_type)'b'));
 assert(p1!=p2);
 Int a(2),b(3);
 pair_id d0(a,'a');
 pair_id d1(a,'b');
 assert(d0!=d1);
 assert(d0<=d1);
 assert(d1>=d0);
 return 0;
 
}


 

<iterator> 中定义了迭代器得使用方法,主要得模版类有:

 插入迭代器

插入迭代器是一种迭代器适配器,带有一个容器参数,并生成一个迭代器,用于在指定的容器中插入元素。通过插入迭代器赋值时,迭代器将会插入一个新的元素。C++语言提供了三种插入器,其差别在于插入元素的位置不同:

back_inserter,创建使用push_back实现插入的迭代器,其使用一个对象作为实参将一个新元素插入到容器得后端
 
front_inserter的操作类似于back_inserter:该函数将创建一个迭代器,调用它所关联的基础容器的push_front成员函数代替赋值操作。
注意:只有当容器提供push_front操作时,才能使用front_inserter。在vector或其他没有push_front运算的容器上使用front_inserter,将产生错误。
 
inserter使用insert实现插入操作,inserter还带有第二个实参:指向插入起始位置的迭代器,inserter总是在它的迭代器参数所标明的位置前面插入新元素。
流迭代器
虽然iostream类型不是容器,但标准库同样提供了在iostream对象上使用的迭代器:istream_iterator用于读取读入流,而ostream_iterator用于写输出流。这些迭代器将它们所对应的流视为特定类型的元素序列。使用流迭代器时,可以用泛型算法从流对象中读数据(或将数据写到流对象中)。
 
 istream_iterator<T> in(strm);  创建从输入流strm中读取T类型对象的istream_iterator对象,strm是一个输入流  istream_iterator<T> in;  istream_iterator对象的超出末端迭代器  ostream_iterator<T> out(strm);  创建将T类型的对象写到输出流strm的ostream_iterator对象  ostream_iterator<T> out(strm, delim);  创建将T类型的对象写到输出流strm的ostream_iterator对象,在写入过程中使用delim作为元素的分隔符。delim是以空字符结束的字符数组
 
   流迭代器只定义了最基本的迭代器操作:自增、引用和赋值。此外,可比较两个istream迭代器是否相等(或不等)。而ostream迭代器则不提供比较运算。
 流迭代器的限制:
(1)不可能从ostream_iterator对象读入,也不可能写到istream_iterator对象中;
(2)一旦给ostream_iterator对象赋了一个值,写入就提交了。赋值后,没有办法再改变这个值。此外,ostream_iterator对象中每个不同的值都只能正好输出一次。
(3)ostream_iterator没有->操作符。
测试:

#include <iostream>
#include <vector>
#include <iterator>
using namespace std;

int main() {
    istream_iterator<int> in_iter(cin);
    istream_iterator<int> eof;

    
//vector<int> vec(in_iter, eof); //do the same work as following loop

    vector<int> vec;
    while (in_iter != eof)
        vec.push_back(*in_iter++); //*in_iter可以取出输入流中得元素
    
    vector<int>::const_iterator it = vec.begin();
    for(; it != vec.end(); ++it)
        cout<<*it<<endl;
    
    return 0;
}
 

#include <iostream>
#include <iterator>
using namespace std;

int main() {
    ostream_iterator<string> out_iter(cout, "/n");
    istream_iterator<string> in_iter(cin), eof;
    while (in_iter != eof)
        *out_iter++ = *in_iter++;
    
    return 0;
}

反向迭代器
 
反向迭代器是一种反向遍历容器的迭代器。也就是,从最后一个元素到第一个元素遍历容器。反向迭代器将自增(和自减)的含义反过来了:对于反向迭代器,++运算将访问前一个元素,而--运算则访问下一个元素。
 
(1)反向迭代器需要使用自减操作符:标准容器上的迭代器(reverse_iterator)既支持自增运算,也支持自减运算。但是,流迭代器由于不能反向遍历流,因此流迭代器不能创建反向迭代器。
(2)可以通过reverse_iterator::base()将反向迭代器转换为普通迭代器使用,从逆序得到普通次序。
 
测试:
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;
int main() {
    string str = "this 'sentence' is a test";
    cout<<str<<endl;
   
    string::iterator it1 = find(str.begin(), str.end(), '/'');
    string::iterator it2 = find(++it1, str.end(), '/'');
    cout<<string(it1, it2)<<endl;
   
    string::reverse_iterator rit1 = find(str.rbegin(), str.rend(), '/'');
    string::reverse_iterator rit2 = find(++rit1, str.rend(), '/'');
    cout<<string(rit1, rit2)<<endl;
    cout<<string(rit2.base(), rit1.base())<<endl;
    getchar();
    return 0;
}
 
不同的迭代器支持不同的操作集,而各种算法也要求相应的迭代器具有最小的操作集。因此,可以将算法的迭代器分为下面五类:
 
 输入迭代器
(input iterator)
 读,不能写。支持的操作集:==, !=, 前缀++, 后缀++, *, ->。例如,find, accumulate算法要求这类迭代器。  输出迭代器
(output iterator)
 写,不能读。支持的操作集:前缀++, 后缀++, *(只能出现在赋值运算的左操作数上)。推出迭代器要求每个迭代器必须正好写入一次。例如,ostream_iterator是输出迭代器,copy算法使用这类迭代器。  前向迭代器(forward iterator)  读和写,支持输入迭代器和输出迭代器提供的所有操作,还支持对同一个元素的多次读写。例如,replace算法需要这种迭代器。  双向迭代器(bidirectional iterator)  读和写,除了支持前向迭代器的所有操作,还支持前缀--和后缀--,即支持双向遍历容器。例如,reverse算法要求这类迭代器。标准库容器中提供的迭代器都至少达到双向迭代器的要求。  随机访问迭代器(random-access iterator)  读和写。提供在常量时间内访问容器任意位置的功能。支持完整的迭代器操作集:1)关系运算:==, !=, <, <=, >, >=;2)算术运算:it + n, it - n, it += n, it -= n以及it1 - it2;3)下标运算:it[n],等价于*(it + n)。需要随机访问迭代器的泛型算法包括sort算法。例如,vector, deque, string迭代器是随机访问迭代器,用作访问内置数组元素的指针也是随机访问迭代器。
 
   除了输出迭代器,其他类别的迭代器形成了一个层次结构:需要低级类别迭代器的地方,可使用任意一种更高级的迭代器。例如,对于需要输入迭代器的算法,可传递前向、双向或随机访问迭代器调用该算法。而反之则不行。注意:向算法传递无效的迭代器类别所引起的错误,无法保证会在编译时被捕获到。
 
   map, set, list类型提供双向迭代器,而string, vector和deque容器上定义的迭代器都是随机访问迭代器,用作访问内置数组元素的指针也是随机访问迭代器。istream_iterator是输入迭代器,ostream_iterator是输出迭代器。
 
   另外,虽然map和set类型提供双向迭代器,但关联容器只能使用这部分算法的一个子集。因为关联容器的键是const对象。因此,关联容器不能使用任何写序列元素的算法。只能使用与关联容器绑在一起的迭代器来提供用于读操作的实参。因此,在处理算法时,最好将关联容器上的迭代器视为支持自减运算的输入迭代器,而不是完整的双向迭代器。

 

<memory> 它以不同寻常得方式为容器中得元素分配存储空间,它同样也为某些算法执行期间产生得临时对象提供机制,主要模版类为:allocator由他产生容器得默认分配器,我们很少需要直接与分配器打交道,默认得分配器已经可以很好得为我们工作了,但它又包含在标准C++库中所定义得每个容器模版类得模版参数里。

原创粉丝点击