专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »C 教程 » 迭代器:C++迭代器简介 »正文

迭代器:C++迭代器简介

来源: 发布时间:星期四, 2009年2月12日 浏览:140次 评论:0


除了使用下标来访问vector对象元素外标准库还提供了另种检测元素思路方法:使用迭代器(iterator)迭代器是种允许员检查容器内元素并实现元素遍历数据类型

标准库为每种标准容器(包括vector)定义了种迭代器类型迭代器类型提供了比下标操作更般化思路方法:所有标准库容器都定义了相应迭代器类型而只有少数容器支持下标操作迭代器对所有容器都适用现代C更倾向于使用迭代器而不是下标操作访问容器元素即使对支持下标操作vector类型也这样

第11章具体讨论迭代器工作原理但在完全了解它复杂实现细节的前我们样可以先使用它

1. 容器iterator类型

每种容器类型都定义了自己迭代器类型如vector:

vector<>::iterator iter;

这条语句定义了个名为iter变量数据类型是由vector<>定义iterator类型每个标准库容器类型都定义了个名为iterator成员这里iterator和迭代器实际类型含义相同

术语:迭代器和迭代器类型

员首次遇到有关迭代器术语时可能会困惑不解产生困惑原因的是由于本书中同个术语iterator表示两个区别事物般性提及是迭代器概念;而特别提及则是由容器定义具体iterator类型如vector<>

重点要理解定义了许多用作迭代器类型这些类型在概念上是相关种类型支持组确定行为(这些行为允许员遍历容器内元素并允许员访问这些元素值)我们就称这种类型为迭代器

区别容器类定义了自己iterator类型用于访问容器内元素换句话说每个容器定义了种名为iterator类型而这种类型支持(概念上)迭代器各种行为



2. begin和end操作

每种容器都定义了对命名为begin和end用于返回迭代器如果容器中有元素由begin返回迭代器指向第个元素:

vector<>::iterator iter = ivec.begin;

上述语句把iter化为由名为beginvector操作返回假设vector不空化后iter即指该元素为ivec[0]

由end操作返回迭代器指向vector“末端元素个”通常称为超出末端迭代器(off-the-end iterator)表明它指向了个不存在元素如果vector为空begin返回迭代器和end返回迭代器相同

由end操作返回迭代器并不指向vector中任何实际元素相反它只是起个哨兵(sentinel)作用表示我们已处理完vector中所有元素

3. vector迭代器自增和解引用运算

迭代器类型定义了些操作来获取迭代器所指向元素并允许员将迭代器从个元素移动到另个元素

迭代器类型可使用解引用操作符(*操作符)来访问迭代器所指向r 元素:

*iter = 0;

解引用操作符返回迭代器当前所指向元素假设iter指向vector对象ivec个元素那么*iter和ivec[0]就是指向同个元素上面这个语句效果就是把这个元素值赋为0

迭代器使用自增操作符(1.4.1节)向前移动迭代器指向容器中下个元素从逻辑上说迭代器自增操作和型对象自增操作类似对象来说操作结果就是把型值“加1”而对迭代器对象则是把容器中迭代器“向前移动个位置”因此如果iter指向第个元素iter指向第 2个元素

由于end操作返回迭代器不指向任何元素因此不能对它进行解引用或自增操作

4. 迭代器其他运算

对可执行于迭代器操作就是比较:用或!=操作符来比较两个迭代器如果两个迭代器对象指向同个元素则它们相等否则就不相等

5. 迭代器应用举例

假设已声明了个vector<>型ivec变量要把它所有元素值重置为0可以用下标操作来完成:

// re all the elements in ivec to 0

for (vector<>::size_type ix = 0; ix != ivec.size; ix)

ivec[ix] = 0;

上述用for循环遍历ivec元素for循环定义了个索引ix每循环迭代次ix就自增1for循环体将ivec每个元素赋值为0

更典型做法是用迭代器来编写循环:

// equivalent loop using iterators to re all the elements in ivec to 0

for (vector<>::iterator iter = ivec.begin;

iter != ivec.end; iter)

*iter = 0; // element to which iter refers to 0

for循环首先定义了iter并将它化为指向ivec个元素for循环条件测试iter是否和end操作返回迭代器不等每次迭代iter都自增1这个for循环效果是从ivec第个元素开始顺序处理vector中元素最后iter将指向ivec中最后个元素处理完最后个元素后iter再增加1就会和end操作返回值相等在这种情况下循环终止

for循环体内语句用解引用操作符来访问当前元素和下标操作符解引用操作符返回值是个左值因此可以对它进行赋值来改变它上述循环效果就是把ivec中所有元素都赋值为0

通过上述对代码详细分析可以看出这段和用下标操作符版本达到相同操作效果:从vector个元素开始把vector中每个元素都置为0

本节给出例子和3.3.2节vector下标操作如果vector为空是安全如果ivec为空则begin返回迭代器不指向任何元素由于没有元素所以它不能指向任何元素——在这种情况下从begin操作返回迭代器和从end操作返回迭代器值相同因此for语句中测试条件立即失败

6. const_iterator

前面用vector::iterator改变vector中元素值每种容器类型还定义了种名为const_iterator类型该类型只能访问容器内元素但不能改变其值



当我们对普通iterator类型解引用时得到对某个元素非const引用(2.5节)而如果我们对const_iterator类型解引用时则可以得到个指向const对象引用(2.4节)如同任何常量该对象不能进行重写

例如如果text是vector<>类型员想要遍历它输出每个元素,可以这样编写:

// use const_iterator because we won't change the elements

for (vector<>::const_iterator iter = text.begin;

iter != text.end; iter)

cout << *iter << endl; // pr each element in text

除了是从迭代器读取元素值而不是对它进行赋值的外这个循环和前个相似由于这里只需要借助迭代器进行读不需要写这里把iter定义为const_iterator类型当对const_iterator类型解引用时返回个const值不允许用const_iterator进行赋值:

for (vector<>::const_iterator iter = text.begin;

iter != text.end; iter)

*iter = " "; // error: *iter is const

使用const_iterator类型时我们可以得到个迭代器它自身值可以改变但不能用来改变其所指向元素可以对迭代器进行自增以及使用解引用操作符来读取值但不能对该元素值赋值

不要把const_iterator对象和constiterator对象混淆起来声明个const迭代器时必须化迭代器旦被化后就不能改变它值:

vector<> nums(10); // nums is nonconst

const vector<>::iterator cit = nums.begin;

*cit = 1; // ok: cit can change its underlying element

cit; // error: can't change the value of cit

const_iterator对象可以用于const vector或非const vector不能改写元素值const迭代器这种类型几乎没什么用处:旦它被化后只能用它来改写其指向元素但不能使它指向任何其他元素:

const vector<> nines(10, 9); // cannot change elements in nines

// error: cit2 could change the element it refers to and nines is const

const vector<>::iterator cit2 = nines.begin;

// ok: it can't change an element value, so it can be used with a const vector<>

vector<>::const_iterator it = nines.begin;

*it = 10; // error: *it is const

it; // ok: it isn't const so we can change its value

// an iterator that cannot write elements

vector<>::const_iterator

// an iterator whose value cannot change

const vector<>::iterator

习题

习题3.17 重做3.3.2节习题用迭代器而不是下标操作来访问vector中元素

习题3.18 编写来创建有10个元素vector对象用迭代器把每个元素值改为当前值2倍

习题3.19 验证习题3.18输出vector所有元素

习题3.20 解释下在上几个习题实现中你用了哪种迭代器并介绍说明原因

习题3.20 何时使用const迭代器?又在何时使用const_iterator?解释两者区别

3.4.1 迭代器算术操作

除了次移动迭代器个元素增量操作符外vector迭代器(很少有其他标准库容器迭代器)也支持其他算术操作这些操作称为迭代器算术操作(iterator arithmetic)包括:

l iter + n

iter - n

可以对迭代器对象加上或减去个整型值这样做将产生个新迭代器其位置在iter所指元素的前(加)或的后(减)n个元素位置加或减的后结果必须指向iter所指vector中某个元素或者是vector末端个元素加上或减去类型应该是vectorsize_type或dference_type类型(参考下面解释)

l iter1 - iter2

该表达式用来计算两个迭代器对象距离该距离是名为dference_typesigned整数类型这里dference_type类型类似于size_type类型也是由vector定义dference_type是signed类型减法运算可能产生负数结果该类型可以保证足够大以存储任何两个迭代器对象间距离iter1和iter2两者必须都指向同vector中元素或者指向vector末端的后个元素

可以用迭代器算术操作来移动迭代器直接指向某个元素例如下面语句直接定位于vector中间元素:

vector<>::iterator mid = vi.begin + vi.size/2;

上述代码用来化mid使其指向vi中最靠近正中间元素这种直接计算迭代器思路方法和用迭代器逐个元素自增操作到达中间元素思路方法是等价但前者效率要高得多

任何改变vector长度操作都会使已存在迭代器失效例如push_back的后就不能再信赖指向vector迭代器值了

习题

习题3.22 如果采用下面思路方法来计算mid会产生什么结果?

vector<>::iterator mid = (vi.begin + vi.end)/2;
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: