C++ 如果增加一个等于 STL 容器的结束迭代器的迭代器会发生什么

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1057724/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:36:43  来源:igfitidea点击:

What happens if you increment an iterator that is equal to the end iterator of an STL container

c++stlvectoriterator

提问by sharptooth

What if I increment an iterator by 2 when it points onto the last element of a vector? In this questionasking how to adjust the iterator to an STL container by 2 elements two different approaches are offered:

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

  • either use a form of arithmetic operator - +=2 or ++ twice
  • or use std::advance()
  • 使用一种算术运算符 - +=2 或 ++ 两次
  • 或使用 std::advance()

I've tested both of them with VC++ 7 for the edge case when the iterator points onto the last element of the STL container or beyond:

当迭代器指向 STL 容器的最后一个元素时,我已经用 VC++ 7 测试了它们的边缘情况:

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

I've seen may times an advise to compare against vector::end() when traversing the vector and other containers:

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

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

Obviously if the iterator is advanced past the last element inside the loop the comparison in the for-loop statement will evaluate to false and the loop will happily continue into undefined behaviour.

显然,如果迭代器前进到循环内的最后一个元素,则 for 循环语句中的比较将评估为 false,并且循环将继续进入未定义的行为。

Do I get it right that if I ever use advance() or any kind of increment operation on an iterator and make it point past the container's end I will be unable to detect this situation? If so, what is the best practice - not to use such advancements?

如果我在迭代器上使用 Advance() 或任何类型的增量操作并使其指向容器的末端,我是否正确地将无法检测到这种情况?如果是这样,最佳实践是什么 - 不使用此类进步?

采纳答案by Naveen

Following is the quote from Nicolai Josuttis book:

以下是 Nicolai Josuttis 书中的引述:

Note that advance() does not check whether it crosses the end() of a sequence (it can't check because iterators in general do not know the containers on which they operate). Thus, calling this function might result in undefined behavior because calling operator ++ for the end of a sequence is not defined

请注意, Advance() 不会检查它是否穿过序列的 end() (它无法检查,因为迭代器通常不知道它们操作的容器)。因此,调用此函数可能会导致未定义的行为,因为未定义为序列末尾调用运算符 ++

In other words, the responsibility of maintaining the iterator within the range lies totally with the caller.

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

回答by Motti

Perhaps you should have something like this:

也许你应该有这样的事情:

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

You can overload this for when iterator_category<Itr>is random_access_iteratorto do something like the following:

您可以在这个过载iterator_category<Itr>random_access_iterator做类似的情况如下:

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

回答by Kostas

You could use the "distance" function between your iterator (it) and the iterator at vec.begin() and compare it with the vector's size (obtained by size()).

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

In that case your for loop would look like this:

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

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

回答by DukeBrymin

The code that Marijn suggests is just slightly wrong (as curiousguy pointed out).

Marijn 建议的代码有点错误(正如好奇人指出的那样)。

The correct version of the last line is:

最后一行的正确版本是:

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

回答by the_drow

I suggest you to take a look at Boost.Range.
It might be safer to use.
It will also be in C++0x.

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

回答by Dolphin

You could also do more comparisons in your for statement:

您还可以在 for 语句中进行更多比较:

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

I don't know how this would perform vs Kostas'ssuggestion, but it feelslike it would be better for a small increment. Of course it would be pretty unmaintainable for a large increment since you need a check for each, but it is another option.

我不知道这与Kostas 的建议相比会有什么表现,但感觉小幅增加会更好。当然,由于您需要对每个增量进行检查,因此对于大增量来说这是非常不可维护的,但这是另一种选择。

I would definitely avoid it if at all possible. If you really need to increment by 2 values at a time, then consider having a vector of std::pair or a vector of a struct with 2 elements.

如果可能的话,我肯定会避免它。如果您确实需要一次增加 2 个值,则考虑使用 std::pair 向量或具有 2 个元素的结构向量。

回答by Steve Gilham

container.end()-- the element just past the end -- is the only defined exterior value.

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

A checked iterator will fault on what is essentially an out-of-range access, but that isn't terribly helpful (especially as the default behaviour is to end the program).

检查的迭代器会在本质上是超出范围的访问时出错,但这并不是很有帮助(特别是因为默认行为是结束程序)。

I think the best practice is "don't do that" -- either check every value of the iterator (preferably in something wrapped as a filter), and only operate on interesting entries, or use the index explicitly with

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

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

回答by Marijn

Even though this question is half a year old, it might still be useful to mention the use of comparison operators > and < to check if you iterated past the end (or the start when iterating back) of the container. For example:

尽管这个问题已经有半年历史了,但提及使用比较运算符 > 和 < 来检查您是否迭代到容器的末尾(或迭代回的起点)可能仍然有用。例如:

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