【问题标题】:How to increment an iterator by 2?如何将迭代器增加 2?
【发布时间】:2010-11-06 15:36:46
【问题描述】:

谁能告诉我如何将迭代器增加 2?

iter++ 可用 - 我必须使用iter+2 吗?我怎样才能做到这一点?

【问题讨论】:

  • 从答案的范围来看,您可能需要澄清您的问题。
  • 是的。它是什么样的迭代器?显示一些代码。

标签: c++ visual-c++ stl iterator


【解决方案1】:

std::advance( iter, 2 );

此方法适用于不是随机访问迭代器的迭代器,但当与随机访问迭代器一起使用时,它仍然可以通过实现进行专门化,使其效率不低于iter += 2

【讨论】:

  • 如果迭代器当前指向最后一个元素会发生什么?增量后它会指向哪里?我尝试使用 VC++ - 它只是前进并且与 vector::end() 比较之后返回 false 。我想这是未定义行为的直接方式。
  • 是的,如果您要使用 '2' 或 +=2 或两个 '++' 执行 std::advance 而不检查中间的 'end',那么您需要一些外部保证,你不会超过一个结束。 (例如,您可能知道您正在遍历一个集合的偶数(从零开始)项目,该集合保证有偶数个项目。)
  • next(iter, 2) 和next(iter, 2)有什么区别
【解决方案2】:

http://www.cplusplus.com/reference/std/iterator/advance/

std::advance(it,n);

在你的情况下,n 是 2。

这个函数的美妙之处在于,如果“it”是一个随机访问迭代器,那么速度很快

it += n
使用

操作(即 vector::iterator)。否则将其呈现为

for(int i = 0; i < n; i++)
    ++it;

(即列表<..>::iterator)

【讨论】:

    【解决方案3】:

    如果您没有可修改的迭代器左值,或者希望获得给定迭代器的副本(保持原始迭代器不变),那么 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&lt;string,string&gt;::iterator iter; for(iter = variations.begin(); iter != variations.end(); iter++) { map&lt;string,string&gt;::iterator it_tmp = std::next(iter, 1); // increment by 1 it_tmp = std::next(iter, 2); // increment by 2 } iter 会增加 2 吗?或 iter 只会影响 it_tmp?
    • @HaniGoc Only it_tmp
    【解决方案4】:

    您可以使用“加法赋值”运算符

    iter += 2;
    

    【讨论】:

    • 我想知道 ++iter++ 是否可以工作,但我认为这会让人感到困惑。
    • 如果迭代器当前指向最后一个元素会发生什么?增量后会指向哪里?
    • @Xetius:你不应该这样做。这是未定义的行为。
    • ++iter++ 绑定为 ++(iter++),iter++ 不是可修改的左值,因此您不能“执行”++(iter++)。如果允许,它可能不会做预期的事情。
    • 这不适用于所有迭代器类型。只需要 RandomAccessIterators 来支持加法。
    【解决方案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
    

    【讨论】:

      【解决方案6】:

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

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

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

      如果你确定你不会越过终点,那么 std::advance(iter, 2 ) 是最好的解决方案。

      【讨论】:

        【解决方案7】:

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

        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);”的时间复杂度。
        【解决方案8】:

        非常简单的答案:

        ++++iter
        

        长答案:

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

        请注意,前缀增量 (++iter) 采用左值并返回左值,而后缀增量 (iter++) 采用左值并返回右值。

        【讨论】:

        • 如果iter 是原始指针(某些迭代器类型可以是),则行为未定义。 ++it; ++it; 很好。
        • 请告诉我这不是一个严肃的答案。
        猜你喜欢
        • 2011-05-06
        • 1970-01-01
        • 2022-01-22
        • 2013-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多