如何将迭代器增加2?


72

有人可以告诉我如何将迭代器增加2吗?

iter++有空iter+2吗-我必须做吗?我该如何实现?


4
从答案范围来看,您可能需要澄清问题。
teabot

是。什么样的迭代器?显示一些代码。
布赖恩·尼尔

Answers:


106

std::advance( iter, 2 );

此方法适用于非随机访问迭代器的迭代器,但实现仍可对其进行专门化,使其效率不低于iter += 2与随机访问迭代器一起使用时的效率。


1
如果迭代器当前指向最后一个元素,将会发生什么?增量后它将指向何处?我用VC ++进行了尝试-它只是前进了,然后与vector :: end()的比较返回false。我想,这是实现不确定行为的直接方法。
sharptooth

1
是的,如果您要使用“ 2”或+ = 2或两个“ ++”执行std :: advance而未在中间检查“ end”,那么您需要一些外部保证来确保您不会超越终点。(例如,您可能知道您正在遍历集合中偶数(从零开始)的项目,该项保证有偶数的项目。)
CB Bailey 2009年

next(iter,2)和next(iter,2)之间有什么区别
m1350


22

如果您没有可修改的迭代器的左值,或者希望获得给定迭代器的副本(保留原始迭代器不变),则C ++ 11附带了新的辅助函数- std::next/ std::prev

std::next(iter, 2);          // returns a copy of iter incremented by 2
std::next(std::begin(v), 2); // returns a copy of begin(v) incremented by 2
std::prev(iter, 2);          // returns a copy of iter decremented by 2

如果我有一个像这样的迭代器: map<string,string>::iterator iter; for(iter = variations.begin(); iter != variations.end(); iter++) { map<string,string>::iterator it_tmp = std::next(iter, 1); // increment by 1 it_tmp = std::next(iter, 2); // increment by 2 }ITER将增加2?还是iter会影响it_tmp?
Hani Goc '16

@HaniGoc只有it_tmp
变形

8

您可以使用“加法分配”运算符

iter += 2;

我想知道++ iter ++是否行得通,但是我认为那只会令人困惑。
Xetius

2
如果迭代器当前指向最后一个元素,将会发生什么?增量后它将指向何处?
sharptooth

4
@Xetius:您不应该这样做。这是未定义的行为。
Naveen

2
++ iter ++绑定为++(iter ++),iter ++不是可修改的左值,因此您不能“做” ++(iter ++)。如果允许,它可能不会执行预期的操作。
CB Bailey

3
这不适用于所有迭代器类型。仅需要RandomAccessIterators支持添加。
史蒂夫·杰索普

5

如果您不知道容器中是否有足够的下一个元素,则需要检查每个增量之间容器的末尾。++和std :: advance都不会为您做到这一点。

if( ++iter == collection.end())
  ... // stop

if( ++iter == collection.end())
  ... // stop

您甚至可以滚动自己的绑定安全高级功能。

如果您确定您不会走到尽头,那么std :: advance(iter,2)是最佳解决方案。


5

我们可以同时使用std :: advancestd :: next,但是两者之间是有区别的。

advance修改其参数,但不返回任何内容。因此它可以用作:

vector<int> v;
v.push_back(1);
v.push_back(2);
auto itr = v.begin();
advance(itr, 1);          //modifies the itr
cout << *itr<<endl        //prints 2

next 返回迭代器的修改后的副本:

vector<int> v;
v.push_back(1);
v.push_back(2);
cout << *next(v.begin(), 1) << endl;    //prints 2

0

假设列表大小可能不是步长的偶数倍,则必须防止溢出:

static constexpr auto step = 2;

// Guard against invalid initial iterator.
if (!list.empty())
{
    for (auto it = list.begin(); /*nothing here*/; std::advance(it, step))
    {
        // do stuff...

        // Guard against advance past end of iterator.
        if (std::distance(it, list.end()) > step)
            break;
    }
}

根据收集的实现,距离计算可能会非常缓慢。下面是最佳的并且更具可读性。可以将闭包更改为实用程序模板,并通过const引用传递列表结束值:

const auto advance = [&](list_type::iterator& it, size_t step)
{
    for (size_t i = 0; it != list.end() && i < step; std::next(it), ++i);
};

static constexpr auto step = 2;

for (auto it = list.begin(); it != list.end(); advance(it, step))
{
    // do stuff...
}

如果没有循环:

static constexpr auto step = 2;
auto it = list.begin();

if (step <= list.size())
{
    std::advance(it, step);
}

“ std :: advance(it,step);”的时间复杂度是多少?
桑吉特·普拉萨德

-7

很简单的答案:

++++iter

长答案:

您确实应该习惯于写作++iter而不是iter++。后者必须返回旧值(副本),该旧值与新值不同;这需要时间和空间。

请注意,前缀增量(++iter)取一个左值并返回一个左值,而后缀递增(iter++)接受一个左值并返回一个右值。


5
未定义的行为ifiter是原始指针(某些迭代器类型可以是原始指针)。++it; ++it;会没事的。
史蒂夫·杰索普

1
请告诉我这不是一个认真的答案。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.