C ++中反向迭代器的非常奇怪的行为

Posted

技术标签:

【中文标题】C ++中反向迭代器的非常奇怪的行为【英文标题】:very weird behaviour of reverse iterator in C++ 【发布时间】:2018-10-11 13:26:25 【问题描述】:

这是我今天在计算机上进行的一项测试,我被要求实现一个具有两个函数的 Gardner 类 - 每个函数都将 Gardner 所在的土地标记为已割草,并将 Gardner 移动 3 个单位到左还是右。如果在 Gardner 的路径上有任何标记为修剪过的土地,他会跳过它并继续前进。

我使用布尔变量向量对土地进行建模。我使用带有前向迭代器的 std::find() 来查找未在正确方向修剪的土地,而我在左方向使用反向迭代器。前向迭代器按预期工作。然而,反向迭代器产生了一些奇怪的结果。更具体地说,例如,在 Visual Studio 的调试器中,它显示反向迭代器指向的值是 false(这是预期的),但是当我取消引用反向迭代器时,我得到了 true。这可以在以下代码中重现,我已附上代码,感谢任何帮助。

#include <iostream>
#include <vector>
#include <algorithm>

class Gardener

public:
    Gardener(int n, int position)
        : mLands(n, false)
        , mPosition(position - 1)
    
    

    /**
    *   \brief Gardener has mowed the lawn at current house and moved left.
    *
    **/
    void mowAndMoveLeft()
    
        mLands[mPosition] = true;
        //auto it = std::find(mHouses.rbegin() + mHouses.size() - mPosition + 1, mHouses.rend(), false);
        //it = std::find(it + 1, mHouses.rend(), false);
        //it = std::find(it + 1, mHouses.rend(), false);
        auto it = mLands.rbegin() + mLands.size() - mPosition + 1;
        int counter = 3;
        while (--counter >= 0)
        
            while (it != mLands.rend())
            
                if (*it == false)
                
                    ++it;
                    break;
                

                ++it;
            
        

        mPosition = mLands.rend() - it;
    

    /**
    *   \brief Gardener has mowed the lawn at current house and moved right.
    *
    **/
    void mowAndMoveRight()
    
        mLands[mPosition] = true;
        auto it = std::find(mLands.begin() + mPosition + 1, mLands.end(), false);
        it = std::find(it + 1, mLands.end(), false);
        it = std::find(it + 1, mLands.end(), false);
        mPosition = it - mLands.begin();
    

    /**
    *   \return house number that gardener is mowing right now.
    *
    **/
    int whereAmI()
    
        return mPosition + 1;
    

private:
    std::vector<bool> mLands;
    std::size_t mPosition;
;

#ifndef RunTests
int main(int argc, const char* argv[])

    Gardener g(10, 2);
    std::cout << g.whereAmI() << '\n';

    g.mowAndMoveRight();
    std::cout << g.whereAmI() << '\n';

    g.mowAndMoveRight();
    std::cout << g.whereAmI() << '\n';

    g.mowAndMoveLeft();
    std::cout << g.whereAmI() << '\n';

#endif

【问题讨论】:

rend() 容器中的第一个元素,而end()则是在最后一个元素之后。这就是问题的症结所在:反向迭代器让人头疼。 欢迎来到 ***.com。请花点时间阅读the help pages,尤其是名为"What topics can I ask about here?" 和"What types of questions should I avoid asking?" 的部分。也请take the tour 和read about how to ask good questions。最后请阅读this question checklist。 更具体地说,“产生了一些奇怪的结果”并不是对所发生情况的很好描述。您需要详细说明细节。 if( something == false )if( something == true ) 看起来很难看。它们已经是布尔值了。 @Bathsheba,它不是。对于外部世界,rend 表示指向第一个元素之前的元素的指针(尽管在内部它指向第一个元素)。您不能取消引用 rend() 来获取第一个元素。 【参考方案1】:

要了解您的反向迭代器发生了什么, 看看reverse_iterator at cppreference。更具体的看base() method:

基迭代器引用 next 的元素(从 std::reverse_iterator::iterator_typeperspective) 到元素 reverse_iterator 当前指向。那是&amp;*(rit.base() - 1) == &amp;*rit

英文:

*rit.base()(属于反向迭代器)将访问 mLands 的一个元素,该元素位于 *rit 必须访问的元素之前。 *rit*rit.base() 之间的这种转换使得mLands.rend() 在逻辑上指向mLands 的第一个元素成为可能。它相当于 mLands.end() 的镜像,指向 mLands 的最后一个元素。

现在,看看您在调试器中看到的内容。最有可能的是,您的调试器向您显示rit.base() 的值,它指向mLands 中的一个元素,而不是rit 在逻辑上指向的元素。这可以解释您在此处看到的差异。对于调试,如果您不确定调试器显示的内容,这里最安全的做法是打印 *rit 的值或将其存储在临时变量中,然后在调试器中检查。

【讨论】:

以上是关于C ++中反向迭代器的非常奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章

c++stl之反向迭代器用法及注意事项!!!

C#C# 迭代器

迭代器的抽象

C++ 的STL中,迭代器那个指针为何++能指向下一个元素?

反向迭代器

Cpp中迭代器的使用和操作