设为首页 加入收藏

TOP

3.4.1 使用迭代器(1)
2013-10-07 16:28:38 来源: 作者: 【 】 浏览:103
Tags:3.4.1 使用

3.4.1  使用迭代器(1)

和指针不一样的是,获取迭代器不是使用取地址符,有迭代器的类型同时拥有返回迭代器的成员。比如,这些类型都拥有名为begin和end的成员,其中begin成员负责返回指向第一个元素(或第一个字符)的迭代器。如有下述语句:

  1. // 由编译器决定b和e的类型;参见2.5.2节(第68页)  
  2. // b表示v的第一个元素,e表示v尾元素的下一位置  
  3. auto b = v.begin(), e = v.end(); //b 和e的类型相同 

nd成员则负责返回指向容器(或string对象)"尾元素的下一位置(one past the end)"的迭代器,也就是说,该迭代器指示的是容器的一个本不存在的"尾后(off the end)"元素。这样的迭代器没什么实际含义,仅是个标记而已,表示我们已经处理完了容器中的所有元素。end成员返回的迭代器常被称作尾后迭代器(off-the-end iterator)或者简称为尾迭代器(end iterator)。特殊情况下如果容器为空,则begin和end返回的是同一个迭代器。

如果容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器。

一般来说,我们不清楚(不在意)迭代器准确的类型到底是什么。在上面的例子中,使用auto关键字定义变量b和e(参见2.5.2节,第68页),这两个变量的类型也就是begin和end的返回值类型,第108页将对相关内容做更详细的介绍。

迭代器运算符

表3.6列举了迭代器支持的一些运算。使用==和!=来比较两个合法的迭代器是否相等,如果两个迭代器指向的元素相同或者都是同一个容器的尾后迭代器,则它们相等;否则就说这两个迭代器不相等。

表3.6:标准容器迭代器的运算符

3.6:标准容器迭代器的运算符

*iter

返回迭代器iter所指元素的引用

iter->mem

解引用iter并获取该元素的名为mem的成员,

等价于(*iter).mem

++iter

iter指示容器中的下一个元素

--iter

iter指示容器中的上一个元素

iter1 == iter2

判断两个迭代器是否相等(不相等),如果两个

迭代器指示的是同一个元素或者它们是同一个

容器的尾后迭代器,则相等;反之,不相等

iter1 != iter2


和指针类似,也能通过解引用迭代器来获取它所指示的元素,执行解引用的迭代器必须合法并确实指示着某个元素(参见2.3.2节,第53页)。试图解引用一个非法迭代器或者尾后迭代器都是未被定义的行为。

举个例子,3.2.3节(第94页)中的程序利用下标运算符把string对象的第一个字母改为了大写形式,下面利用迭代器实现同样的功能:
 

  1. string s("some string");  
  2. if (s.begin() != s.end()) {     // 确保s非空  
  3.     auto it = s.begin();    // it表示s的第一个字符  
  4.     *it = toupper(*it);         // 将当前字符改成大写形式  
  5. }  

本例和原来的程序一样,首先检查s是否为空,显然通过检查begin和end返回的结果是否一致就能做到这一点。如果返回的结果一样,说明s为空;如果返回的结果不一样,说明s不为空,此时s中至少包含一个字符。

我们在if内部,声明了一个迭代器变量it并把begin返回的结果赋给它,这样就得到了指示s中第一个字符的迭代器,接下来通过解引用运算符将第一个字符更改为大写形式。和原来的程序一样,输出结果将是:
 

  1. Some string 

将迭代器从一个元素移动到另外一个元素

迭代器使用递增(++)运算符(参见1.4.1节,第12页)来从一个元素移动到下一个元素。从逻辑上来说,迭代器的递增和整数的递增类似,整数的递增是在整数值上"加1",迭代器的递增则是将迭代器"向前移动一个位置"。

因为end返回的迭代器并不实际指示某个元素,所以不能对其进行递增或解引用的操作。

之前有一个程序把string对象中第一个单词改写为大写形式,现在利用迭代器及其递增运算符可以实现相同的功能:
 

  1. // 依次处理s的字符直至我们处理完全部字符或者遇到空白  
  2. for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it)  
  3.     *it = toupper(*it); // 将当前字符改成大写形式  

和3.2.3节(第94页)的那个程序一样,上面的循环也是遍历s的字符直到遇到空白字符为止,只不过之前的程序用的是下标运算符,现在这个程序用的是迭代器。

循环首先用s.begin的返回值来初始化it,意味着it指示的是s中的第一个字符(如果有的话)。条件部分检查是否已到达s的尾部,如果尚未到达,则将it解引用的结果传入isspace函数检查是否遇到了空白。每次迭代的最后,执行++it令迭代器前移一个位置以访问s的下一个字符。

循环体内部和上一个程序if语句内的最后一句话一样,先解引用it,然后将结果传入toupper函数得到该字母对应的大写形式,再把这个大写字母重新赋值给it所指示的字符。

关键概念:泛型编程(www.cppentry.com)

原来使用C或Java的程序员在转而使用C++(www.cppentry.com)语言之后,会对for循环中使用!=而非<进行判断有点儿奇怪,比如上面的这个程序以及94页的那个。C++(www.cppentry.com)程序员习惯性地使用!=,其原因和他们更愿意使用迭代器而非下标的原因一样:因为这种编程(www.cppentry.com)风格在标准库提供的所有容器上都有效。

之前已经说过,只有string和vector等一些标准库类型有下标运算符,而并非全都如此。与之类似,所有标准库容器的迭代器都定义了==和!=,但是它们中的大多数都没有定义<运算符。因此,只要我们养成使用迭代器和!=的习惯,就不用太在意用的到底是哪种容器类型。
 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇3.4 迭代器介绍 下一篇3.4.1 使用迭代器(2)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: