想知道从事件循环中不断迭代的列表中删除元素的最佳方法是什么。 我有一个事件循环,其中我的列表正在更新
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;
});
这会给出列表迭代运行时错误,因为循环中的迭代器变得无效。解决这种情况的最佳方法是什么?
答案 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
的元素。