从事件的迭代列表中删除元素

时间:2019-04-16 18:43:45

标签: c++ list

想知道从事件循环中不断迭代的列表中删除元素的最佳方法是什么。 我有一个事件循环,其中我的列表正在更新

for (auto pIt = this->particles.begin(); pIt != this->particles.end(); pIt++) {
    (*pIt)->Update(system, gameTime);
}

在某个基于事件的时间,我必须从列表中删除随机元素。 使用以下命令在单独的函数中进行处理:

this->particles.remove_if([particle](Particle *ptc)->bool {
    return ptc == particle;
});

这会给出列表迭代运行时错误,因为循环中的迭代器变得无效。解决这种情况的最佳方法是什么?

2 个答案:

答案 0 :(得分:0)

擦除功能必须有权访问循环中使用的迭代器(使其成为成员变量),并且如果该迭代器指向要删除的元素,则递增迭代器。这样,您可以防止循环迭代器因擦除而失效。

示例:

#include <iostream>
#include <list>

struct Explosion;

struct Particle {
    void update(Explosion&);
};

struct Explosion {
    std::list<Particle> particles;
    std::list<Particle>::iterator particle_iter;

    void update() {
        for(particle_iter = particles.begin(); particle_iter != particles.end(); ) {
            auto to_call = particle_iter++;
            to_call->update(*this);
        }
    }

    template<class Condition>
    void filter(Condition condition) {
        for(auto i = particles.begin(); i != particles.end();) {
            auto to_remove = i++;
            if(condition(*to_remove)) {
                // Remove the element.
                if(particle_iter == to_remove)
                    particle_iter = i;
                particles.erase(to_remove);
            }
        }
    }
};

void Particle::update(Explosion& explosion) {
    explosion.filter([this](Particle& other) { return this == &other; });
    // The above ends up destroying this object.
    // Cannot no longer access this and should only return.
}

int main() {
    Explosion explosion{{Particle{}, Particle{}}, {}};
    std::cout << explosion.particles.size() << '\n';
    explosion.update();
    std::cout << explosion.particles.size() << '\n';
}

答案 1 :(得分:0)

我假设元素的删除发生在Update()函数内部,并且“列表”实际上是std::list而不是std::vector

不要在循环头中执行pIt++。相反,请在调用pIt++之前先进行Update()。在返回的原始对象上调用Update()

for (auto pIt = this->particles.begin(); pIt != this->particles.end(); ) {
    auto pForCall = *(pIt++);
    pForCall->Update(system, gameTime);
}

另一种行不通的情况是,要删除的元素不是我们正在调用Update的元素。