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
What happens if you increment an iterator that is equal to the end iterator of an STL container
提问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_iterator
to 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