以下程序至少有四个与iterator相关的问题:
int main()
{
vector<Date> e;
copy(istream_iterator<Date>(cin),
istream_iterator<Date>(),
back_inserter(e));
vector<Date>::iterator first =
find(e.begin(),e.end(),"01/01/95");
vector<Date>::iterator last =
find(e.begin(),e.end(),"12/31/95");
*last = "12/30/95";
copy(first,last,
ostream_iterator<Date>(cout,"\n"));
e.insert(--end(),TodaysDate());
copy(first,last,
ostream_iterator<Date>(cout,"\n"));
}
解答:
vector<Date> e;
copy(istream_iterator<Date>(cin),
istream_iterator<Date>(),
back_inserter(e));
目前为止一切都正确,Date class提供了一个输入操作符(>>),以便istream_iterator<Date>得以从cin stream读取Date资料。上述copy算法会把Date填充到vector内。
vector<Date>::iterator first =
find(e.begin(),e.end(),"01/01/95");
vector<Date>::iterator last =
find(e.begin(),e.end(),"12/31/95");
*last = "12/30/95";
错误:上述last可能不是有效迭代器,可能是e.end(),不能解引用一个e.end()。
copy(first,last,
ostream_iterator<Date>(cout,"\n"));
错误,这可能是非法的,因为[first,last)可能不是有效范围;实际上,first可能在last之后。
e.insert(--end(),TodaysDate());
第一个错误:--end()可能是非法的,vector<Date>::iterator经常只是一个Date*,C++语言不允许修改内置类型的临时变量。下面代码也可能非法:
Date* f();//函数返回一个Date*
p = --f();//错误,但可以写成f()-1
幸运的是,vector<Date>::iterator是一个随机迭代器,因此编写如下的正确代码将不会有任何的损失:
e.insert(end()-1,TodaysDate());
第二个错误,如果end()为空,所有迭代器将是无效的迭代器。
copy(first,last,
ostream_iterator<Date>(cout,"\n"));
}
错误:first和last可能不是有效迭代器。
本例e.insert()操作的结果是vector可能增长也可能不增长,这意味着内存可能移动也可能不移动。由于这种不确定性,我们必须认为容器的任何已存在的迭代器都是可能无效的。这种情况下,如果内存确实移动了,那么这个问题copy()函数会发生难以诊断的core dump。
总结:
永远不要解引用无效迭代器。
使用迭代器时,注意四个主要问题:
- 有效值:迭代器可以解引用么?
- 有效生存期,使用迭代器时,仍然有效么?
- 有效范围:一对迭代器是一个有效范围么?first确实在last之前(或相等)吗?两个迭代器确实都指向同一容器的元素吗?
- 非法的内置类型操作:例如,是否由代码企图取修改内置类型的临时对象,正如上述的“--end()”。(幸运的是,编译器通常会捕捉这种错误的,对于指向类类型的(非内置类型))迭代器,为了语法方便,库的作者一般允许这样的操作。)