C++之STL(十):迭代器适配器{(插入迭代器back_insert_iterator)、IO流迭代器(istream_iterator、ostream_iterator)}

一、迭代器适配器

反向迭代器

插入迭代器

IO流迭代器


其中反向迭代器可以参考以前的文章


二、插入迭代器

插入迭代器实际上是一个输出迭代器(*it=; ++)


back_insert_iterator
back_inserter


front_insert_iterator
front_inserter


先来看示例:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <vector>
#include <algorithm>

using  namespace std;

void ShowVec( const vector< int> &v)
{
     for (vector< int>::const_iterator it = v.begin(); it != v.end(); ++it)
    {
        cout << *it <<  ' ';
    }
    cout << endl;
}
int main( void)
{
     int a[] = { 12345};
    vector< int> v(a, a +  5);
    vector< int> v2;

    back_insert_iterator<vector< int> > bii(v);
     //*bii = 6;
    bii =  6;
    ShowVec(v);

    back_insert_iterator<vector< int> > bii2(v2);
    copy(v.begin(), v.end(), bii2);
    ShowVec(v2);

    back_inserter(v) =  7;
    ShowVec(v);

    copy(v.begin(), v.end(), back_inserter(v2));
    ShowVec(v2);


     return  0;
}

查看back_insert_iterator 类的定义:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// TEMPLATE CLASS back_insert_iterator
template< class _Container>
class back_insert_iterator
    :  public _Outit
{
     // wrap pushes to back of container as output iterator
public:
     typedef _Container container_type;
     typedef  typename _Container::reference reference;

     typedef _Range_checked_iterator_tag _Checked_iterator_category;

     explicit back_insert_iterator(_Container &_Cont)
        : container(&_Cont)
    {
         // construct with container
    }

    back_insert_iterator<_Container> & operator=(
         typename _Container::const_reference _Val)
    {
         // push value into container
        container->push_back(_Val);
         return (* this);
    }

    back_insert_iterator<_Container> & operator*()
    {
         // pretend to return designated value
         return (* this);
    }

    back_insert_iterator<_Container> & operator++()
    {
         // pretend to preincrement
         return (* this);
    }

    back_insert_iterator<_Container>  operator++( int)
    {
         // pretend to postincrement
         return (* this);
    }

protected:
    _Container *container;   // pointer to container
};

类内部的成员container 保存的是指向容器的指针,重载了*, ++, = 等运算符,* 和 ++ 返回的都是迭代器本身,主要看 赋值运算符:


container->push_back(_Val); 即调用了容器的push_back 函数, 所以可以直接写 bii = 6; 即将6压入容器末尾。程序中还调用了copy 


函数,回顾copy 源码,主要是以下代码:


for (; _First != _Last; ++_Dest, ++_First)



        *_Dest = *_First;


其中,_First 和 _Last 分别是v.begin() 和 v.end(), _Dest 是 bii2,上面也说了,*_Dest 返回的是自身,而且++_Dest 返回的也是自


身,从_First 遍历到 _Last ,调用back_insert_iterator 类的operator=,即不断地执行container->push_back(_Val); 容器的元素位置会


自动移动。


再来看back_inserter 函数:

 C++ Code 
1
2
3
4
5
6
7
// TEMPLATE FUNCTION back_inserter
template< class _Container>  inline
back_insert_iterator<_Container> back_inserter(_Container &_Cont)
{
     // return a back_insert_iterator
     return (std::back_insert_iterator<_Container>(_Cont));
}

实际上返回的也是一个back_insert_iterator 对象,所以能直接替换掉bii2。


当然了,与back 配对的就是front,back 是末尾插入,front 是头端插入,需要注意的是front_insert_iterator 的operator= 调用了


push_front 函数,故如vector 是没有实现push_front 的,不能使用front_insert_iterator ,而list 和 deque 是可以使用的。


示例代码如下:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>

using  namespace std;

void ShowList( const list< int> &v)
{
     for (list< int>::const_iterator it = v.begin(); it != v.end(); ++it)
    {
        cout << *it <<  ' ';
    }
    cout << endl;
}

int main( void)
{
     int a[] = { 12345};
    list< int> l(a, a +  5);
    list< int> ll;

    front_insert_iterator<list< int> > fii(l);
    fii =  0;
    ShowList(l);

    copy(l.begin(), l.end(), front_inserter(ll));
    ShowList(ll);
     return  0;
}


三、IO流迭代器


输出流迭代器(ostream_iterator)


*it=; ++


输入流迭代器(istream_iterator)

=*it; ->; ++; ==; !=


直接来看示例代码:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>

using  namespace std;

int main( void)
{
    vector< int> v;

     // copy from cin to vector
    copy(istream_iterator< int>(cin), istream_iterator< int>(), back_inserter(v));

     // copy from vector to cout
    copy(v.begin(), v.end(), ostream_iterator< int>(cout,  " "));
    cout << endl;

     return  0;
}

首先来看istream_iterator 的源码:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// TEMPLATE CLASS istream_iterator
template <  class _Ty,
          class _Elem =  char,
          class _Traits = char_traits<_Elem>,
          class _Diff = ptrdiff_t >
class istream_iterator
    :  public iterator < input_iterator_tag, _Ty, _Diff,
       const _Ty *,  const _Ty & >
{
     // wrap _Ty extracts from input stream as input iterator
     typedef istream_iterator<_Ty, _Elem, _Traits, _Diff> _Myt;
public:
     typedef _Elem char_type;
     typedef _Traits traits_type;
     typedef basic_istream<_Elem, _Traits> istream_type;

#if _SECURE_SCL
     typedef _Range_checked_iterator_tag _Checked_iterator_category;
#endif

    istream_iterator()
        : _Myistr( 0)
    {
         // construct singular iterator
    }

    istream_iterator(istream_type &_Istr)
        : _Myistr(&_Istr)
    {
         // construct with input stream
        _Getval();
    }

     const _Ty & operator*()  const
    {
         // return designated value

         return (_Myval);
    }

     const _Ty * operator->()  const
    {
         // return pointer to class object
         return (& ** this);
    }

    _Myt & operator++()
    {
         // preincrement

        _Getval();
         return (* this);
    }


protected:
     void _Getval()
    {
         // get a _Ty value if possible
         if (_Myistr !=  0 && !(*_Myistr >> _Myval))
            _Myistr =  0;
    }

    istream_type *_Myistr;   // pointer to input stream
    _Ty _Myval;  // lookahead value (valid if _Myistr is not null)
};

上面只截取了部分用上的源码,istream_iterator 类有两个成员,一个是输入流对象指针,一个是输入的值,如


 istream_iterator<int>(cin)  调用构造函数,初始化_Myistr,且通过函数_Getval() 初始化_Myval,_Getval() 调用输入流的


operator>> 将键盘输入的值赋予_Myval。而 istream_iterator<int>() 呢初始化_Myistr 为0,此时_Myval 被忽略。


回顾copy 源码,主要是以下代码:


for (; _First != _Last; ++_Dest, ++_First)



        *_Dest = *_First;


此时_First 和 _Last 是 istream_iterator<int> 类型,_Dest是back_insert_iterator 类型,而判断_First 和 _Last 是否相等,其实


operator != 里面是判断它们的成员指针_Myistr 是否相等,在_Getval 函数可以看到,当我们输入错误(类型不匹配)或者ctrl+z,


则 istream_iterator<int>(cin) 的_Myistr 被置为0,此时本来 istream_iterator<int>() 的_Myistr 就为0,故相等,不再继续执行下去。


如果不等,即输入正确的话,*First 调用istream_iterator 类的operator* 直接返回_Myval ,接着调用back_insert_iterator 类的


operator=,即调用container 的push_back ,将_Myval 压入容器。++_Dest 是没什么效果的,而++_First 在istream_iterator 类的


operator++ 中会继续调用_Getval,即继续获得键盘输入覆盖_Myval。


再来看ostream_iterator 的源码:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// TEMPLATE CLASS ostream_iterator
template< class _Ty,
     class _Elem =  char,
     class _Traits = char_traits<_Elem> >
     class ostream_iterator
        :  public _Outit
    {    // wrap _Ty inserts to output stream as output iterator
public:
     typedef _Elem char_type;
     typedef _Traits traits_type;
     typedef basic_ostream<_Elem, _Traits> ostream_type;

#if _SECURE_SCL
     typedef _Range_checked_iterator_tag _Checked_iterator_category;
#endif

    ostream_iterator(ostream_type& _Ostr,
         const _Elem *_Delim =  0)
        : _Myostr(&_Ostr), _Mydelim(_Delim)
        {    // construct from output stream and delimiter
        }

    ostream_iterator<_Ty, _Elem, _Traits>&  operator=( const _Ty& _Val)
        {    // insert value into output stream, followed by delimiter
        *_Myostr << _Val;
         if (_Mydelim !=  0)
            *_Myostr << _Mydelim;

         return (* this);
        }

    ostream_iterator<_Ty, _Elem, _Traits>&  operator*()
        {    // pretend to return designated value
         return (* this);
        }

    ostream_iterator<_Ty, _Elem, _Traits>&  operator++()
        {    // pretend to preincrement
         return (* this);
        }

protected:

     const _Elem *_Mydelim;   // pointer to delimiter string (NB: not freed)
    ostream_type *_Myostr;   // pointer to output stream
    };

ostream_iterator 类也有两个成员,一个是输出流对象指针,一个是字符串指针,看上面的copy 代码,此时_First 和 _Last 


分别是v.begin() 和 v.end(),_Dest是 ostream_iterator<int> 类型,*_Dest 返回自身,++_Dest 也返回自身,而在operator= 函数中


*_Myostr << _Val;


if (_Mydelim != 0)


*_Myostr << _Mydelim;


即判断如果还有传入字符串,则在输出元素值之后,还伴随着字符串的输出。所以示例代码中的输出是伴随着空格的。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本版本与网上其他资源不同之处在于,此版本可进行编辑,搜索,已进行内容识别扫描。可全选,可编辑,可剪切文字。 部分目录如下: 目录 第一篇预备知识 第1 章C++ 编程技术...................................................... 3 1-1 C++与C 语言的区别................................................... 4 1-1-1 文件扩展名的改变,.............................................. 4 1-1-2 简化输入/输出手段.............................................. 5 1-1-3 数据类型声明的改变,............................................ 5 1-1-4 动态内存分配运算符的使用....................................... 6 1-1-5 弓I 用(References) 类型, ··················•················•"'''8 1-1-6 const 语义的扩展................................................ 9 1-1-7 指针声明类型与对象类型相一致.................................. 13 1-1-8 int 与char 不再等价............................................. 13 1-1-9 结构数据类型的变化............................................ 13 1-1-10 数组和指针技术的不同......................................... 14 1-2 C++存储技术........................................................ 15 1-2 一I C++存储类型.................................................. 15 I6I7 ..... .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. •. .• •. .• .. .. .. .. .. .. .. .. .. .. .. .. . 期 符存 饰生 修的 取象 存对 廿廿 I2I32 ~3 c c 1-3 C++ 函数技术........................................................ 19 1-3-1 类的构造函数、析构函数与赋值函数,..... - ........ - .............. 19 1-3-2 在派生类中实现类的基本函数,................... _ ............... 29 1-3-3 内联函数技术,........ ................................... 30 3133 ..... .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . 现 实 术的 技制 数机 函象 元对 友向 由 曰1. l -C 1 4 3337 ..... .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . 术术 技技 承载 继重 的数 类函 l4l44 3 ~ 3840 ..... .. .. .. .. .. .. •. .• .. .. .. .. .. .. .. .. .. .. .. •. .• .. •. .• •. •• .• .. .. .. .. .. .. .. .. .. •. •• .• . 术 技 类 术象 技抽 载和 重数 符函 算虚 运纯 l4l34 4 1-5 小结...............................................

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值