繁体   English   中英

C ++ Vector.erase()最后一个元素破坏了迭代器

[英]C++ Vector.erase() last element corrupts iterator

我目前遇到vector.erase()的问题。

vector<gameObject> gameObjects;

for (auto it = gameObjects.end() - 1; it != gameObjects.begin();)
    {
        if ((it)->getDestroyed()) {
            it = gameObjects.erase(it);
        }
        else {
            --it;
        }
    }

所以gameObject是游戏中所有内容的基类,它有一个bool标志,基本上告诉我们对象是否被破坏。 如果设置了标志,则应从向量中删除该标志。

class gameObject
{
protected:
    bool toBeDestroyed;
public:
    bool getDestroyed();
    void markToDestroy();
};

现在第一个被破坏的对象被成功地从向量中移除然后我得到一个错误:迭代器不是可解除引用的,指向第73行(?)处的向量库。

然后我检查msvc调试器。 在数据预览中,它显示迭代器指向gameObjects的最后/最新元素。 然后将其删除(擦除(it))并且AFTERWARDS数据预览不会更改,并且调用它 - > getDestroyed()会导致错误消息。

调试断言失败了! 矢量迭代器不可解除引用。

PS:我检查了cplusplus.com,vector.erase应该返回一个新的,有效的迭代器,所以我不知道我在哪里弄乱它。

€:在我被告知擦除 - 移除成语后,我继续前进,最后得到以下内容,但不能编译。 由于我的函数是gameObject的成员,我不知道如何成功调用remove_if。 谢谢

gameObjects.erase(remove_if(gameObjects.begin(), gameObjects.end(), gameObject::getDestroyed), gameObjects.end());

€2:很多人指出第一个对象没有被检查。 我应该指出这一点,但第一个元素始终是玩家,不应该删除。 不过,谢谢你的评论。 我会尝试一个简单的前进循环而不会太花哨^^。

€3:我尝试了Jonathan Mees建议的代码,但我得到了完全相同的错误消息。 我会试着找出它到底发生了什么但是我不能再把断点放到擦除部分了。 会有点乱。

€4:通过删除else {}条件并始终减少迭代器来解决问题。 再次感谢您的回复。

假设你的向量中有2个对象,最后一个被标记为已销毁。 当你调用erase ,它将返回一个新的有效迭代器,指向擦除元素后面的元素。 擦除元素后面没有元素,因此返回的迭代器是gameObjects.end() 然后继续到循环的顶部并取消引用此迭代器,这是无效的。 如果希望指向有效元素,则需要在擦除后递减迭代器。

另一个注意事项:如果您想要删除第一个元素,则不会。 当迭代器== gameObjects.begin() ,你的循环退出,所以永远不会检查第一个元素。

有什么理由你想反过来这样做吗? 如果没有具体原因,我建议您使用@Borgleader推荐的方法。

你的循环有点混乱 - 你向后迭代,忽略第一个元素,并多次测试一些元素。 我可以建议将rbegin()作为替代方案吗?

vector::erase返回:

Iterator跟随最后删除的元素。 如果迭代器pos引用最后一个元素,则返回end()迭代器。

这意味着vector::erase永远不会返回vector::begin (除非你删除了容器中唯一的元素。)所以在调用vector::erase之后it总会被解除引用。 即使通过调用vector::erase返回vector::end也会被解除引用,这当然是非法的。

而不是这个循环,考虑使用为此目的设计的remove_if

gameObjects.erase(remove_if(begin(gameObjects),
                            end(gameObjects),
                            [](const auto& i){ return i.getDestroyed(); }), end(gameObjects));

编辑:

我注意到你尝试在编辑中使用它。 您不能使用裸函数指针作为谓词。 如果你想避免lambda,你应该考虑使用mem_fn

gameObjects.erase(remove_if(begin(gameObjects),
                            end(gameObjects),
                            mem_fn(&gameObject::getDestroyed)), end(gameObjects));

实例

如果阅读该行很困难,可随意使用尽可能多的变量:

auto p = mem_fn(&gameObject::getDestroyed);
auto result = remove_if(begin(gameObjects), end(gameObjects), p);

gameObjects.erase(result, end(gameObjects));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM