外国网站签到做任务每月挣钱,展示型手机网站模板下载,网页设计实验报告小结,阿里巴巴怎样做网站3.4迭代器介绍
我们已经知道可以使用下标运算符来访问string对象的字符或vector对象的元素#xff0c;还有另外一种更通用的机制也可以实现同样的目的#xff0c;这就是迭代器#xff08;iterator#xff09;。在第II部分中将要介绍#xff0c;除了vector之外#xff0c…3.4迭代器介绍
我们已经知道可以使用下标运算符来访问string对象的字符或vector对象的元素还有另外一种更通用的机制也可以实现同样的目的这就是迭代器iterator。在第II部分中将要介绍除了vector之外标准库还定义了其他几种容器。所有标准库容器都可以使用迭代器但是其中只有少数几种才同时支持下标运算符。严格来说string对象不属于容器类型但是string支持很多与容器类型类似的操作。vector支持下标运算符这点和string-样string支持迭代器这也和vector是一样的。类似于指针类型参见2.3.2节第47页迭代器也提供了对对象的间接访问。就迭代器而言其对象是容器中的元素或者string对象中的字符。使用迭代器可以访问某个元素迭代器也能从一个元素移动到另外一个元素。迭代器有有效和无效之分这一点和指针差不多。有效的迭代器或者指向某个元素或者指向容器中尾元素的下一位置其他所有情况都属于无效。
3.4.1使用迭代器
和指针不一样的是获取迭代器不是使用取地址符有迭代器的类型同时拥有返回迭代器的成员。比如这些类型都拥有名为begin和end的成员其中begin成员负责返回指向第一个元素或第一个字符的迭代器。如有下述语句/ / 由编译器决定b 和 e 的类型参见2.5.2节 第 61页 // b 表示v 的第一个元素e 表示v 尾元素的下一位置auto b v.begin , e v.end ; //b 和 e 的类型相同end成员则负责返回指向容器或string对象“尾元素的下一位置onepasttheend”的迭代器也就是说该迭代器指示的是容器的一个本不存在的“尾后offtheend”元素。这样的迭代器没什么实际含义仅是个标记而已表示我们已经处理完了容器中的所有元素。end成员返旧]的迭代器常被称作尾后迭代器off^the-enditerator或者简称为尾迭代器enditerator特殊情况下如果容器为空则begin和end返回的是同一个迭代器。如果容器为空则begin和 end返回的是同一个迭代器都是尾后迭代器。 一般来说我们不清楚不在意迭代器准确的类型到底是什么。在上面的例子中使用auto关键字定义变量b 和 e 参见2.5.2节第 61页这两个变量的类型也就是 begin 和 end的返回值类型第 97页将对相关内容做更详细的介绍。
迭代器运算符
表3.6列举了迭代器支持的一些运算。使用和来比较两个合法的迭代器是否相等如果两个迭代器指向的元素相同或者都是同一个容器的尾后迭代器则它们相等否则就说这两个迭代器不相等iter-mem 等效于 *item).mem指针类似也能通过解引用迭代器来获取它所指示的元素执行解引用的迭代器必须合法并确实指示着某个元素参见2.3.2节第48页。试图解引用一个非法迭代器或者尾后迭代器都是未被定义的行为。举个例子3.2.3节第84页中的程序利用下标运算符把string对象的第一个字母改为了大写形式下面利用迭代器实现同样的功能本例和原来的程序一样首先检查S 是否为空显然通过检查begin和 end返回的结果 是否一致就能做到这一点。如果返回的结果一样说明s为空如果返回的结果不一样 说明s不为空此时s 中至少包含一个字符。 我们在if内部声明了一个迭代器变量it并把begin返回的结果赋给它这样就得到了指示s 中第一个字符的迭代器接下来通过解引用运算符将第一个字符更改为大写 形式。
将迭代器从一个元素移动到另外一个元素
迭代器使用递增运算符参见1.4.1节第11页来从一个元素移动到下一个元素。从逻辑上来说迭代器的递增和整数的递增类似整数的递增是在整数值上“加1”,迭代器的递增则是将迭代器“向前移动一个位置”。因为end返回的迭代器并不实际指示某个元素所以不能对其进行递增或解 引用的操作和 3.2.3节 第 84页的那个程序一样上面的循环也是遍历s 的字符直到遇到空白字符 为止只不过之前的程序用的是下标运算符现在这个程序用的是迭代器。循环首先用s .begin的返回值来初始化it,意味着it指示的是s 中的第一个字符 如果有的话。条件部分检查是否已到达s 的尾部如果尚未到达则将it解引用的结果传入isspace函数检查是否遇到了空白。每次迭代的最后,执行it令迭代器平移 一个位置以访问s 的下一个字符。 循环体内部和上一个程序if语句内的最后一句话一样先解引用it,然后将结果传入 toupper函数得到该字母对应的大写形式再把这个大写字母重新赋值给it所指示的字符。for循环 使用 ! 进行比较这个支持的没有! 广泛
迭代器类型
就像不知道string和vector的size_type成员参见3.2.2节第79页到底是什么类型一样一般来说我们也不知道其实是无须知道迭代器的精确类型。而实际上 那些拥有迭代器的标准库类型使用iterator和const_iterator来表示迭代器的类型iterator 参考链接const_iterator和常量指针参见2.4.2节第56页差不多能读取但不能修改它所指的元素值。相反iterator的对象可读可写。如果vector对象或string对象是-个常量只能使用const_iterator如果vector对象或string对象不是常量那么既能使用iterator也能使用const_iteratorbegin和end运算符
begin和end返回的具体类型由对象是否是常量决定如果对象是常量begin和end返回const_iterator如果对象不是常量返回iteratorvectorintv;有时候这种默认的行为并非我们所要。在6.2.3节(第191页)中将会看到如果对象只需读操作而无须写操作的话最好使用常量类型(比如const_iterator)。为了便于专门得到const_iterator类型的返回值,C11新标准引入了两个新函数分别是cbegin和cendauto it3 v . cbegin () ; // it3 的类型是 vectorint: : const_iterator类似于begin和end,上述两个新函数也分别返回指示容器第一个元素或最后元素下一位置的迭代器。有所不同的是不论vector对象(或string对象)本身是否是常量返回值是const_iterator
结合解引用和成员访问操作
解引用迭代器可获得迭代器所指的对象如果该对象的类型恰好是类就有可能希望进一步访问它的成员。例如对于一个由字符串组成的vector对象来说要想检查其元素是否为空令it是该vector对象的迭代器只需检查it所指字符串是否为空就可以了其代码如下所示(*it).empty()注意(*it).empty()中的圆括号必不可少具体原因将在4.1.2节(第121页)介绍该表达式的含义是先对it解引用然后解引用的结果再执行点运算符(参见1.5.2节第20页)。如果不加圆括号点运算符将由it来执行而非it解引用的结果上面第二个表达式的含义是从名为it的对象中寻找其em pty成员显然it是一个迭代 器它没有哪个成员是叫empty的所以第二个表达式将发生错误。 为了简化上述表达式C语言定义了箭头运算符(-)箭头运算符把解引用和成员访问两个操作结合在一起也就是说it-mem和表达的意思相同。例如假设用一个名为text的字符串向量存放文本文件中的数据其中的元素或者是一句话或者是一个用于表示段落分隔的空字符串。如果要输出text中第一段的内容可以利用迭代器写一个循环令其遍历text,直到遇到空字符串的元素为止我们首先初始化it令其指向text的第-个元素循环重复执行直至处理完了text的所有元素或者发现某个元素为空。每次迭代时只要发现还有元素并且尚未遇到空元素就输出当前正在处理的元素。值得注意的是因为循环从头到尾只是读取text的元素而未向其中写值所以使用了cbegin和cend来控制整个迭代过程。
某些对vector对象的操作会使迭代器失效
3.3.2节 (第 90页)曾经介绍过虽然vector对象可以动态地增长但是也会有一些副作用。已知的一个限制是不能在范围for循环中向vector对象添加元素。另外一个限制是任何一种可能改变vector对象容量的操作比如push_back,都会使该vector对象的迭代器失效。9.3.6节第315页将详细解释迭代器是如何失效的。迭代器 是指end 和 cend尾后迭代器谨记但凡是使用了迭代器的循环体都不要向迭代器所属的容器添加元素
3.4.2迭代器运算
迭代器的递增运算令迭代器每次移动一个元素所有的标准库容器都有支持递增运算的迭代器。类似的也能用和对任意标准库类型的两个有效迭代器参见3.4节第95页进行比较。string和vector的迭代器提供了更多额外的运算符一方面可使得迭代器的每次移动跨过多个元素另外也支持迭代器进行关系运算。所有这些运算被称作迭代器运算其细节由表3.7列出。迭代器的算术运算
可以令迭代器和一个整数值相加或相减其返回值是向前或向后移动了若干个位置的迭代器。执行这样的操作时结果迭代器或者指示原vector对象或 string 对象内的一个元素或者指示原vector对象 或 string对象尾元素的下一位置。举个例子下面的代码得到一个迭代器它指向某vector对象中间位置的元素auto mid vi.begin() vi.size() / 2; / / 计算得到最接近vi中间元素的一个迭代器如果vi有20个元素vi.size()/2得10,此例中即令mid等于vi.begin()10。已知下标从0开始则迭代器所指的元素是vi[10],也就是从首元素开始向前相隔10个位置的那个元素。只要两个迭代器指向的是同一个容器中的元素或者尾元素的下一位置就能将其相减所得结果是两个迭代器的距离。所谓距离指的是右侧的迭代器向前移动多少位置就能追上左侧的迭代器其类型是名为difference_type的带符号整型数。string和vector都定义了difference_type,因为这个距离可正可负所以difference_type是带符号类型的。
使用迭代器运算
使用迭代器运算的一个经典算法是二分搜索。二分搜索从有序序列中寻找某个给定的值。二分搜索从序列中间的位置开始搜索如果中间位置的元素正好就是要找的元素搜索完成如果不是假如该元素小于要找的元素则在序列的后半部分继续搜素假如该元素大于要找的元素则在序列的前半部分继续搜索。在缩小的范围中计算一个新的中间元素并重复之前的过程直至最终找到目标或者没有元素可供继续搜索。程序的一开始定义了三个迭代器beg指向搜索范围内的第一个元素、end指向尾元素的下一位置、mid指向中间的那个元素。初始状态下搜索范围是名为text的vectorstring的全部范围。循环部分先检查搜索范围是否为空如果mid和end的当前值相等说明已经找遍了所有元素。此时条件不满足循环终止。当搜索范围不为空时可知mid指向了某个元素检查该元素是否就是我们所要搜索的如果是也终止循环。当进入到循环体内部后程序通过某种规则移动beg或者end来缩小搜索的范围。如果mid所指的元素比要找的元素sought大可推测若text含有sought,则必出现在mid所指元素的前面。此时可以忽略mid后面的元素不再查找并把mid赋给end即可。另一种情况如果*mid比soughtZJS则要找的元素必出现在mid所指兀素的后面。此时通过令beg指向mid的下一个位置即可改变搜索范围。因为已经验证过mid不是我们要找的对象所以在接下来的搜索中不必考虑它。循环过程终止时mid或者等于end或者指向要找的元素。如果mid等于end,说明text中没有我们要找的元素。