如果迭代器的增量等于 STL 容器的结束迭代器,会发生什么情况

如果迭代器指向向量的最后一个元素时,它的值增加2呢?在 这个问题中,如何通过两个元素将迭代器调整为 STL 容器,提供了两种不同的方法:

  • 要么使用一种形式的算术运算符-+ = 2或 + + 两次
  • 或使用 std: : forward ()

我已经用 VC + + 7测试过这两种方法,当迭代器指向 STL 容器的最后一个元素或者更多元素的时候:

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

在遍历向量和其他容器时,我看到过多次建议与 Vector: : end ()进行比较:

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

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

如果我曾经在迭代器上使用 forward ()或任何类型的增量操作,并且使它指向容器的末端,我将无法检测到这种情况,这样做对吗?如果是这样,什么是最佳实践——不使用这些进步?

44720 次浏览

container.end()——刚过末尾的元素——是唯一定义的外部值。

一个检查过的迭代器会在本质上是一个超出范围的访问上出错,但是这并没有太大的帮助(特别是当缺省行为是结束程序时)。

我认为最佳实践是“不要这样做”——要么检查迭代器的每个值(最好是包装为筛选器的内容) ,只对感兴趣的条目进行操作,要么显式地使用索引

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

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

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;

以下引自 Nicolai Josuttis 的书:

请注意,forward ()不检查 是否跨越了 序列(它不能检查,因为 迭代器通常不知道 容器)。 因此,调用此函数可能 导致未定义行为的原因是 调用运算符 + + 表示 序列没有定义

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

您可以使用迭代器(it)和 vec.start ()的迭代器之间的“距离”函数,并将其与向量的大小(通过 size ()获得)进行比较。

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

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

你也可以在 for 语句中进行更多的比较:

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

我不知道这将如何执行与 Kostas 的的建议,但它 感觉喜欢它会更好的一个小的增量。当然,对于一个大的增量来说,它是相当不可维护的,因为您需要为每个增量检查,但它是另一个选项。

如果可能的话,我一定会避免的。如果您确实需要一次增加2个值,那么可以考虑使用 std: : p 的向量或者包含2个元素的 struct 的向量。

我建议你看看 加速,射程
用它可能更安全。
它也将使用 C + + 0x。

尽管这个问题已经出现了半年,但是提到比较操作符 > 和 < 的使用可能仍然有用,可以检查是否迭代过容器的结束(或者当迭代回来时的开始)。例如:

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

Marijn 建议的代码只是稍微有点错误(就像好奇的家伙指出的那样)。

最后一行的正确版本是:

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