【问题标题】:Iterating over and removing elements from a Vector. Error:Vector iterator not Incrementable迭代并从 Vector 中删除元素。错误:向量迭代器不可递增
【发布时间】:2016-11-12 18:13:46
【问题描述】:

我正在尝试遍历存储的std::unique_ptr<Enemy> 的向量,以检查它们是否与player 的攻击发生冲突。如果是,我想从向量中删除Enemy。 但是,当我这样做时,我得到了错误:

文件:c:\program files (x86)\microsoft visual studio 14.0\vc\include\vector 线路:102 表达式:向量迭代器不可递增

代码如下:

if(actionCnt > 0)
{
    sf::FloatRect* playerAction = player->action(actionCnt);

    if (!enemies.empty()) {
        for (auto&i : enemies) {
            if (playerAction->intersects(i->getBox())) {
                i->kill();
                enemies.erase(std::remove(enemies.begin(), enemies.end(), i));
            }
        }
    }

    delete playerAction;
    playerAction = NULL;
}

所以本质上,如果玩家触发了攻击,actionCnt 会变为 1 并且该段被执行。

playerAction 是一个被移动以模拟挥杆动作的矩形,所以我在这里检查矩形是否与敌人发生碰撞,如果是的话会杀死它。

我正在使用 SFML 库,但这些类的作用应该很明显。

目前我场上只有 1 个敌人来测试这些东西。所以当我点击它时,enemies 向量应该是空的。

【问题讨论】:

  • 无论这是否是问题所在,相信我,您不想在使用范围 for 进行迭代时使用 erase
  • 所以我查看了@LogicStuff 发布的线程并尝试将其放入while 循环中,但是我无法使用迭代器引用enemies 向量中的元素例如:playerAction->intersects(*iter->getBox()) 给我一个错误说"std::unique_ptr<Enemy, std::default_delete<Enemy>>" has no member "getBox"
  • 你需要(*iter)->getBox()

标签: c++ vector sfml


【解决方案1】:

代码中的auto 将返回向量容器内的类型。它不会给你迭代器。您可以使用经典的 for 循环并使用迭代器擦除元素,而不是基于范围的 for 循环。

if (!enemies.empty())
{
    for (auto itr = std::begin(enemies); itr!=std::end(enemies); ++itr)
    {
       if ((*itr)->hit)
       {
          (*itr)->kill();
          enemies.erase(itr);
       }
    }
}

或者您可以在 std::remove_if 中使用 lambda 函数并在一行中完成整个操作。这实际上被称为 erase-remove idiom(更多 here)。简而言之,remove_if 以保留顺序的方式移动(移动)容器中从 lambda 函数返回 false 的所有元素,并将迭代器返回到最后一个元素之后的那个。从 lambda 函数返回 true 的元素被移动到向量的末尾,并且仍然是可解引用的,但未定义。要完全擦除元素,调用向量的擦除函数来删除从容器的逻辑端(从 std::remove_if 的迭代器)到物理端(vector.end())的所有元素。

if (!enemies.empty())
   enemies.erase(std::remove_if(enemies.begin(),enemies.end(),[](const auto &itr){return itr->hit;}),std::end(enemies)); 

此外,基于范围的 for 循环用于当您想要对元素执行操作时不改变容器本身。为了更安全的代码,您可以使用 while 循环而不是基于范围的 for 循环。

if (!enemies.empty())
{
    auto itr = std::begin(enemies); 
    while (itr != std::end(enemies) )
    {
        if ((*itr)->hit)
        {
           (*itr)->kill();
           enemies.erase(itr);
        }
        ++itr;
    } 
}

您可以在这里查看代码:http://rextester.com/EHLB11709 我试图模仿你的游戏逻辑,只关注删除部分。从输出中您会看到第 6 个元素已被删除。

此外,如果您想从向量中删除所有内容,您应该使用clear()

【讨论】:

    猜你喜欢
    • 2018-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 2016-04-15
    相关资源
    最近更新 更多