您的位置:首页 > 其它

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

2015-01-10 23:00 375 查看
一、迭代器适配器

反向迭代器

插入迭代器

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[] = {1, 2, 3, 4, 5};

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[] = {1, 2, 3, 4, 5};

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,



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

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

ostream_iterator<int>

*_Myostr << _Val;

if (_Mydelim != 0)

*_Myostr << _Mydelim;

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

参考:

C++ primer 第四版

Effective C++ 3rd

C++编程规范
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐