当它指向vector的最后一个元素时,如果我将迭代器增加2,该怎么办?

在这个问题中 ,如何通过2个元素来调整迭代器到STL容器,提供了两种不同的方法:

  • 要么使用算术运算符的forms – + = 2或++两次
  • 或使用std :: advance()

当迭代器指向STL容器的最后一个元素或更高版本时,我已经用VC ++ 7testing了它们的边界情况:

vector<int> vec; vec.push_back( 1 ); vec.push_back( 2 ); vector<int>::iterator it = vec.begin(); advance( it, 2 ); bool isAtEnd = it == vec.end(); // true it++; // or advance( it, 1 ); - doesn't matter isAtEnd = it == vec.end(); //false it = vec.begin(); advance( it, 3 ); isAtEnd = it == vec.end(); // false 

我曾经见过在遍历向量和其他容器的时候可能会有一个build议与vector :: end()进行比较:

 for( vector<int>::iterator it = vec.begin(); it != vec.end(); it++ ) { //manipulate the element through the iterator here } 

显然,如果迭代器超越了循环内部的最后一个元素,那么for循环语句中的比较将被计算为false,并且循环将愉快地继续进行未定义的行为。

如果我使用advance()或迭代器上的任何types的递增操作并使其指向容器的末尾,我将无法检测到这种情况吗? 如果是这样,最好的做法是什么 – 不使用这种进步?

以下是来自Nicolai Josuttis的书:

请注意,advance()不检查它是否跨越序列的end()(它不能检查,因为迭代器通常不知道它们在哪个容器上运行)。 因此,调用此函数可能会导致未定义的行为,因为未定义调用operator ++作为序列的结尾

换句话说,将迭代器维护在范围内的责任完全在于调用者。

也许你应该有这样的东西:

 template <typename Itr> Itr safe_advance(Itr i, Itr end, size_t delta) { while(i != end && delta--) i++; return i; } 

iterator_category<Itr>random_access_iterator时,你可以重载这个来做类似下面的事情:

 return (delta > end - i)? end : i + delta; 

你可以在你的迭代器(it)和vec.begin()的迭代器之间使用“距离”函数,并将其与vector的大小(size()获得)进行比较。

在这种情况下,您的for循环将如下所示:

 for (vector<int>::iterator it = vec.begin(); distance(vec.begin(), it) < vec.size(); ++it) { // Possibly advance n times here. } 

container.end() – 刚刚结束的元素 – 是唯一定义的外部值。

检查过的迭代器会对本质上是超出范围的访问发生故障,但这不是非常有用(特别是因为默认行为是结束程序)。

我认为最好的做法是“不要这样做” – 要么检查迭代器的每个值(最好是包装成filter的东西),只对有趣的条目进行操作,或者明确地使用索引

for(int i = 0; i <vec.size(); i + = 2){…}

你也可以在你的陈述中做更多的比较:

 for( vector<int>::iterator it = vec.begin(); it != vec.end() && it+1 != vec.end(); it+=2 ) { //manipulate the element through the iterator here } 

我不知道Kostas的build议是如何实现的 ,但是觉得对于小的增量会更好。 当然这对于一个大的增量来说是相当难以维护的,因为你需要对每一个进行检查,但是这是另一种select。

如果可能的话,我一定会避免的。 如果你真的需要一次增加2个值,那么考虑使用一个std :: pair向量或一个包含2个元素的结构向量。

我build议你看看Boost.Range 。
使用可能更安全。
它也将在C ++ 0x。

Marijnbuild议的代码只是稍微错了(正如古怪的指出的那样)。

最后一行的正确版本是:

 bool isPastEnd = it >= vec.end(); 

尽pipe这个问题已经有半年了,但提及使用比较运算符>和<来检查是否迭代了容器的最后(或重新开始)时仍然有用。 例如:

 vector<int> vec; vec.push_back( 1 ); vec.push_back( 2 ); vector<int>::iterator it = vec.begin(); it+=10; //equivalent to advance( it, 10 ) bool isPastEnd = it > vec.end(); //true