【问题标题】:for loop doesn't end when condition is met满足条件时for循环不会结束
【发布时间】:2012-02-21 04:46:14
【问题描述】:
for(it = gameObjects.begin();it!=gameObjects.end();it++){
    it->second->update(frameTime);
    if(it->second->getSprite()->GetPosition().y > 500){
        std::cout << "Removing enemy" << std::endl;
        std::map<sf::String,VisibleGameObject*>::iterator itor = Remove(it->second->getName());
        if(itor!=gameObjects.end()){
            std::cout << "itor doesn't equal" << std::endl;
            it=itor;
        }else{
            std::cout << "itor = end" << std::endl;
            it=itor;
        }
    }
}

一打印itor = end,就会出错——“map set iterator not incrementable”。我认为 for 循环应该在它再次增加之前结束,因为 it!=gameObjects.end() 在此之后将是错误的。在 else 语句中添加break 即可解决问题。

为什么没有break 就不能工作?我假设与检查条件时相比,迭代器何时递增。

【问题讨论】:

    标签: c++ for-loop conditional-statements


    【解决方案1】:

    你假设正确。迭代器在循环结束时递增,然后检查条件。

    所以在打印“itor = end”之后,它会递增到gameObjects.end()++,这当然是无效的。您可以通过检查循环内的itor == gameObjects.end(),然后中断来解决。

    编辑:正如 cmets 中所指出的,您最好从循环中删除 ++it,以避免在删除元素后跳过该元素。例如:

    for( it = gameObjects.begin(); it!=gameObjects.end(); ) {
        ...
        if(it->second->getSprite()->GetPosition().y > 500) {
            it = Remove( it->second->getName() );
        } else {
            ++it;
        }
    }
    

    【讨论】:

    • 这里还是有问题。在it=itor;it++ 之后,您只是跳过了一个元素。如果需要连续删除两个,代码将错过第二个。
    • 抱歉,还是有点棘手。如果删除第一个元素,则不能减少迭代器(因为它将是 == begin())。标准是从for 中删除it++,然后要么 删除一个元素或递增迭代器。
    • @BoPersson 啊,是的,感谢您指出这一点。显然,我对我的例子没有像最初的问题那样关注。现在修复(我希望)
    【解决方案2】:

    for 循环首先执行语句(增加值)然后检查条件。问题是 for 循环会在迭代器到达地图末尾后尝试递增迭代器。

    【讨论】:

      【解决方案3】:
      std::map<sf::String,VisibleGameObject*>::iterator itor = Remove(it->second->getName());
      .
      .
      .
      it=itor;
      

      是你的问题。

      在某个时间点,remove 语句从gameObjects 中删除最后一项,然后您执行it=itor,将其设置为gameObjects 中的最后一项,而不检查您的循环条件。 for 循环在++ 的循环结束时递增,所以你已经过了gameObjects 的结尾。

      【讨论】:

        【解决方案4】:

        假设您可以不使用控制台输出,您可以稍微简化循环,只需执行以下操作:

        for(it = gameObjects.begin();it!=gameObjects.end();){
            it->second->update(frameTime);
            it = it->second->getSprite()->GetPosition().y > 500 
                 ? Remove(it->second->getName()); 
                 : it++;
        }
        

        【讨论】:

        • 谢谢,我不知道 C++ 中的语法,但在返回之前我确实尝试了一些类似的方法
        • @PigHead 主体的最后一条语句也可以放在循环头中,使主体成为单线,但我个人认为这比在循环头中包含这么长的语句更容易阅读
        猜你喜欢
        • 2021-11-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多