SGI 2.9.1源码手札 stream Iterator:istream_iterator 和ostream_iterator 知识核心点

短期代码阅读主要基于SGI的STL,测试环境则是GCC_4.8.3_STL和VS_STL。暂时不去配置BOOST等库STL细节。待续

1、istream_iterator 输入流迭代器

1)没有operator=操作,因为只读,不可写,所以编译不支持。迭代器句柄保存当前已读取到的数据。

_GLIBCXX_CONSTEXPR istream_iterator()
      : _M_stream(0), _M_value(), _M_ok(false) {}

      ///  Construct start of input stream iterator.
      istream_iterator(istream_type& __s)
      : _M_stream(&__s)
      { _M_read(); }

在对象声明即初始化的世界,三个版本的构造函数代码是类似的,有个小坑:除了初始化的默认参数是不一样的之外,在使用绑定至正确输入对象时,自动调用了读取操作。

2)有个读取操作为protected,向外提供,使用句柄的形式听过数据访问操作.。在SGI中的read操作和GCC:_M_read实现比较类似,都是单独定义一个状态控制量,根据控制量去确定是否进行输入迭代,正确情况下会调用输入对象的输入符操作。重点:当出现错误的情况并不会修正迭代器指向,这点和VS:_Getval 的实现不一样。

void
      _M_read()
      {
	_M_ok = (_M_stream && *_M_stream) ? true : false;
	if (_M_ok)
	  {
	    *_M_stream >> _M_value;
	    _M_ok = *_M_stream ? true : false;
	  }
      }

而在VS:_Getval 中,实现由些差别:

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

VS出现输入错误终止的情况下会把当前迭代器的值置为0,也就是说不在绑定至任何输入流,具有不可重复性操作。基于这点,我们无法再多平台上根据输入流的状态进行容错处理,至少vs是不支持的,在1:处理完输入流的状态后得2:重新设置迭代器的状态才行继续输入(SGI和GCC则没有步骤2可以继续使用输入迭代器)。

3、迭代器进行迭代时,

operator++

完成读取数据的操作。外界使用其接口读取数据则是另外一个接口:解引用取值操作。也就是时候但迭代失败时,保留的是上一个数据

istream_iterator&
      operator++()
      {
	__glibcxx_requires_cond(_M_ok,
				_M_message(__gnu_debug::__msg_inc_istream)
				._M_iterator(*this));
	_M_read();
	return *this;
      }

正确的使用方式如下:

std::istream_iterator<int> in_it(cin),eos;//输入输出的迭代器结束符和文件等结束符不一样,是迭代器的判定不一样,所以定义一个空迭代器判定是否为终止状态

	while (!in_it._Equal(eos))
	{
		cout<<*in_it;
		cout<<endl;
		++in_it;
	}

关于结束判定的这点,因为源码实现有点不一样,GCC实现如下:在控制量

 bool
      _M_equal(const istream_iterator& __x) const
      { return (_M_ok == __x._M_ok) && (!_M_ok || _M_stream == __x._M_stream); }

而SGI port的则增加输入流状态处理,如首先校验两个迭代器是否完成输入操作,没有的话继续执行(这个估计得看操作系统的操作,一旦IO设备未置位读取完成,就继续执行读取,不出现多次读取的处理是交由操作系统或相关api去处理,而不是在这里控制。)是:

bool _M_equal(const _Self& __x) const {
    if (!_M_read_done) {
      _M_read();
    }
    if (!__x._M_read_done) {
      __x._M_read();
    }
    return (_M_ok == __x._M_ok) && (!_M_ok || _M_stream == __x._M_stream);
  }

当然SGI的代码则是在operator==操作符中实现

template <class _Tp, class _Distance>
inline bool operator==(const istream_iterator<_Tp, _Distance>& __x,
                       const istream_iterator<_Tp, _Distance>& __y) {
  return (__x._M_stream == __y._M_stream &&
          __x._M_end_marker == __y._M_end_marker) ||
         __x._M_end_marker == false && __y._M_end_marker == false;
}

最后来到比较坑的代码中:

SGI:

istream_iterator() : _M_stream(&cin), _M_end_marker(false) {}
  istream_iterator(istream& __s) : _M_stream(&__s) { _M_read(); }

SGI PORT:

istream_iterator() : _M_stream(0), _M_ok(false), _M_read_done(true) {}
  istream_iterator(istream_type& __s) : _M_stream(&__s), _M_ok(false), _M_read_done(false) {} // 重点,没有进行首次读取
reference operator*() const { //采用惰性处理,蛮好的,适合理解
    if (!_M_read_done) {
      _M_read();
    }
    return _M_value;
  }

GCC:

_GLIBCXX_CONSTEXPR istream_iterator()
      : _M_stream(0), _M_value(), _M_ok(false) {}

      ///  Construct start of input stream iterator.
      istream_iterator(istream_type& __s)
      : _M_stream(&__s)
      { _M_read(); }

VS:

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

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

实际上真正按照标准实现的是STL port,可是其他家成为事实的标准,都在有绑定状态优先执行首次读取。不过不用担心,所有的算法库都是先读取首操作采取执行operator++操作,实际上的数据处理不对出现说丢失状态。

无论哪个版本,最后表现的结果都是一致的(除效率外),基于这点,在基本原理实现上,我优先阅读SGI和GCC的源码,偶尔辅助VS的实现。

ostream_iterator 的源码思想也类似,重载了operator=,不提供指针偏移等操作(迭代操作在于原位),就不继续贴代码啦。

都是定义一个空迭代作为哨兵。

std::istream_iterator<int> in_it(cin),eos;

	while (!(in_it==eos))
	{
		cout<<*in_it;
		cout<<endl;
		++in_it;
	}
时间: 2024-10-29 04:01:53

SGI 2.9.1源码手札 stream Iterator:istream_iterator 和ostream_iterator 知识核心点的相关文章

安卓源码总体结构(2)基础知识汇总

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ packages/ |– apps (各种应用程序,如联系人.浏览器等) |– experimental (一些实验性的项目,如错误报告) |– inputmethods (输入法相关) |– providers (各种数据源实现,如联系人数据.媒体库等信息) |– wallpapers (各种壁纸程序) Android Framework功能介绍 android.app :提供**的程序模型和基本的运行环境. android.co

安卓源码总体结构(1)基础知识汇总

– Makefile (全局的Makefile文件) – bionic (Bionic含义为仿生,这里面是一些基础的C库源代码) – bootloader (引导加载器) build目录中的内容不是目标所用的代码,而是编译和配置所需要的脚本和工具) – build (build目录中的内容不是目标所用的代码,而是编译和配置所需要的脚本和工具) – cts (Android兼容性测试套件标准) – libcore (核心库相关) Dalvik虚拟机 针对嵌入式设备优化的Java Java虚拟机)

bw信用盘源码-初学web开发需要掌握哪些知识

如下. 第一步:学习HTML和CSSOA信用盘架设q<319.135.503.1> HTML(超文本标记语言)是网页的核心,学好HTML是成为Web开发人员的基本条件.HTML很容易学习的,但也很容易误用,要学精还得费点功夫. 随着HTML5的发展和普及,了解HTML5也将成为Web开发人员的必修课. 涉及到网页外观时,就需要学习CSS了,它可以帮你把网页做得更美观. 利用HTML和CSS模拟一些你所见过的网站的排版和布局(色彩,图片,文字样式等等). 第二步:学习javascript,了解D

Gson 源码解读

开源库地址:https://github.com/google/gson 解读版本:2.7 Gson是一个可以用来将Java对象转换为JSON字符串的Java库.当然,它也可以把JSON字符串转换为等价的Java对象.网上已经有了不少可将Java对象转换成JSON的开源项目.但是,大多数都要求你在Java类中加入注解,如果你无法修改源码的话就比较坑爹了,此外大多数开源库并没有对泛型提供完全的支持.于是,Gson在这两个重要的设计目标下诞生了.Gson可以作用于任意的Java对象(包括接触不到源码

STL源码剖析之allocator(1)

空间配置器(allocator)这个概念在阅读源码之前我根本没有听过,原以为内存分配都是使用new和delete运算符(注意和operator new.placement new.operator delete以及placement delete不同).在实际使用STL编程时也很少会遇到自己去实现一个空间配置器的情况.事实上,STL容器背后都要依靠空间配置器去分配空间.在阅读容器等STL组件的实现之前如果不了解空间配置器的原理,就会造成阅读上的困难.在侯捷的<STL源码剖析>一书中说道:为什么

【转】Android 二维码 生成和识别(附Demo源码)--不错

原文网址:http://www.cnblogs.com/mythou/p/3280023.html 今天讲一下目前移动领域很常用的技术——二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS.Android.WP都有相关支持的软件.之前我就想了解二维码是如何工作,最近因为工作需要使用相关技术,所以做了初步了解.今天主要是讲解如何使用ZXing库,生成和识别二维码.这篇文章实用性为主,理论性不会讲解太多,有兴趣可以自己查看源码. 1.ZXing库介绍 这里简单介绍一下ZXing库.ZXin

豆瓣Redis解决方案Codis源码剖析:Proxy代理

豆瓣Redis解决方案Codis源码剖析:Proxy代理 1.预备知识 1.1 Codis Codis就不详细说了,摘抄一下GitHub上的一些项目描述: Codis is a proxy based high performance Redis cluster solution written in Go/C, an alternative to Twemproxy. It supports multiple stateless proxy with multiple redis instan

[转] - 使用Qt作窗口截屏(含源码)

截屏(screenshot),就是将屏幕上的东西拷贝下来存成图片文件.介绍的好像有点多余:(,那我们就直接切入正题. QPixmap提供了两个函数grabWidget和grabWindow可以将屏幕上的窗体存成一个QPixmap格式的图片,很容易再将QPixmap存成文件.函数使用很简单,两行代码就可以.QPixmap pixmap = QPixmap::grabWidget(this);//this是调用该函数的QWidget *指针pixmap.save(“widget.png”,”png”

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析,左值与右值

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析 by 小威威 1. 知识引入 在C++编程中,动态分配的内存在使用完毕之后一般都要delete(释放),否则就会造成内存泄漏,导致不必要的后果.虽然大多数初学者都会有这样的意识,但是有些却不以为意.我曾问我的同学关于动态内存的分配与释放,他的回答是:"只要保证new和delete成对出现就行了.如果在构造函数中new(动态分配内存),那么在析构函数中delete(释放)就可以避免内存泄漏了!" 事实果真如此么?