代码改变世界

《Effective STL 读书笔记》 第四章 迭代器

2011-08-20 13:38  咆哮的马甲  阅读(408)  评论(0)    收藏  举报
作者:咆哮的马甲
出处:http://www.cnblogs.com/arthurliu/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
转载请保持文档的完整性,严禁用于任何商业用途,否则保留追究法律责任的权利。

第二十六条: iterator优先于const_iterator, reverse_iterator以及const_reverse_iterator

对于容器类container<T>而言,

  • iterator的功效相当与T*
  • const_iterator的功效相当于 const T*
  • reverse_iterator与const_reverse_iterator与前两者类似,只是按照反向遍历

它们之间相互转换的关系如图


从iterator到const_iterator和reverse_iterator存在隐式转换,从reverse_iterator到const_iterator也存在隐式转换。

通过base()可以将reverse_iterator转换为iterator,同样可以将const_reversse_iterator转换为const_iterator,但是转换后的结果并不指向同一元素(有一个偏移量)


第二十七条: 使用distance和advance将容器的const_iterator转换成iterator
 

对于大多数的容器,const_cast并不能将const_iterator转换为iterator。即使在某些编译器上可以将vector和string的const_iterator转换为iterator,但存在移植性的问题

通过distance和advance将const_iterator转换为iterator的方法

 1 vector<Widget> v;
2
3 typedef vector<Widget>::const_iterator ConstIter;
4 typedef vector<Widget>::iterator Iter;
5
6 ConstIter ci;
7
8 ... //使ci指向v中的元素
9 Iter i = v.begin();
10 advance(i,distance<ConstIter>(i,ci));

  



第二十八条: 正确理解由reverse_iterator的base()成员函数所产生的iterator的用法

使用reverse_iterator的base()成员函数所产生的iterator和原来的reverse_iterator之间有一个元素的偏移量。

Picture2_thumb[7]


容器的插入、删除和修改操作都是基于iterator的,所以对于reverse_iterator,必须通过base()成员函数转换为iterator之后才能进行增删改的操作。

  • 对于插入操作而言,新插入的元素都在3和4之间,所以可以直接使用insert(ri.base(),xxx)
  • 对于修改和删除操作,由于ri和ri.base()并不指向同一元素,所以在修改和删除前,必须修正偏移量

修正ri和ri.base()偏移量的做法

 1 set<Widget> s;
2
3 typedef set<Widget>::reverse_iterator RIter;
4
5 RIter ri;
6
7 ... //使ri指向v中的元素
8
9 s.erase(--ri.base()); //直接修改函数返回的指针不能被直接修改。 如果iterator是基于指针实现的,代码将不具有可以执行。
10
11 s.erase((++ri).base()); //具备可移植行的代码

  


第二十九条: 对于逐个字符的输入请考虑使用istreambuf_iterator

常用的istream_iterator内部使用的operator>>实际上执行了格式化的输入,每一次的operator>>操作都有很多的附加操作

  • 一个内部sentry对象的构造和析构(设置和清理行为的对象)
  • 检查可能影响行为的流标志(比如skipws)
  • 检查可能发生的读取错误
  • 出现错误时检查流的异常屏蔽标志以决定是否抛出异常


对于istreambuf_iterator,它直接从流的缓冲区中读取下一个字符,不存在任何的格式化,所以效率相对istream_iterator要高得多。


对于非格式化的输出,也可以考虑使用ostreambuf_iterator代替ostream_iterator。(损失了格式化输出的灵活性)