如果您递增一个等于 STL 容器的结束迭代器的迭代器,会发生什么

发布于 2024-07-25 21:29:47 字数 1038 浏览 3 评论 0原文

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

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

我已经用 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

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

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

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

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

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

  • either use a form of arithmetic operator - +=2 or ++ twice
  • or use 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:

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:

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.

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

望笑 2024-08-01 21:29:47

以下是 Nicolai Josuttis 书中的引述:

请注意,advance() 不会检查
是否越过 a 的 end()
序列(它无法检查,因为
迭代器一般不知道
他们操作的容器)。
因此,调用这个函数可能
导致未定义的行为,因为
调用 ++ 来结束 a
序列未定义

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

Following is the quote from Nicolai Josuttis book:

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

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

别在捏我脸啦 2024-08-01 21:29:47

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

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

iterator_categoryrandom_access_iterator 时,你可以重载它来执行如下操作:

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

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:

return (delta > end - i)? end : i + delta;
一花一树开 2024-08-01 21:29:47

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

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

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

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()).

In that case your for loop would look like this:

for (vector<int>::iterator it = vec.begin(); distance(vec.begin(), it) < vec.size(); ++it)
{
     // Possibly advance n times here.
}
眼趣 2024-08-01 21:29:47

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

最后一行的正确版本是:

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

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

The correct version of the last line is:

bool isPastEnd = it >= vec.end();
薄暮涼年 2024-08-01 21:29:47

您还可以在 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::pair 向量或具有 2 个元素的结构体向量。

You could also do more comparisons in your for statement:

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's suggestion, but it feels like 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.

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.

浊酒尽余欢 2024-08-01 21:29:47

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

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

闻呓 2024-08-01 21:29:47

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

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

我认为最好的做法是“不要这样做”——要么检查迭代器的每个值(最好是在包装为过滤器的东西中),并且只对感兴趣的条目进行操作,要么显式使用索引

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

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

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) {...}
小糖芽 2024-08-01 21:29:47

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

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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文