C++ 从事件的迭代列表中删除元素
想知道从事件循环中不断迭代的列表中删除元素的最佳方法是什么。 我有一个更新列表的事件循环C++ 从事件的迭代列表中删除元素,c++,list,C++,List,想知道从事件循环中不断迭代的列表中删除元素的最佳方法是什么。 我有一个更新列表的事件循环 for (auto pIt = this->particles.begin(); pIt != this->particles.end(); pIt++) { (*pIt)->Update(system, gameTime); } 在某个基于事件的时间,我必须从列表中删除一个随机元素。 它在一个单独的函数中处理,使用: this->particles.remove_if([
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;
});
这会导致列表迭代运行时错误,因为循环中的迭代器无效。解决这种情况的最佳方法是什么?擦除函数必须能够访问循环中使用的迭代器(使其成为成员变量),如果迭代器指向要删除的元素,则递增迭代器。这样可以防止循环迭代器因擦除而失效 例如:
#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';
}
#包括
#包括
结构爆炸;
结构粒子{
无效更新(爆炸&);
};
结构爆炸{
列出粒子;
std::list::iterator particle\u iter;
无效更新(){
对于(particle_iter=particles.begin();particle_iter!=particles.end();){
自动调用=粒子调用++;
调用->更新(*此项);
}
}
模板
空隙过滤器(条件){
对于(自动i=particles.begin();i!=particles.end();){
自动删除=i++;
如果(条件(*删除)){
//拆下该元件。
如果(粒子=移除)
粒子_iter=i;
粒子。擦除(删除);
}
}
}
};
空心粒子::更新(爆炸和爆炸){
explosion.filter([this](粒子和其他){返回this==&other;});
//以上内容最终会破坏此对象。
//无法再访问此文件,只能返回。
}
int main(){
爆炸爆炸{{粒子{},粒子{},{};
std::cout我假设元素的删除发生在Update()
函数中,“list”实际上是std::list
而不是std::vector
不要在循环头中执行pIt++
。而是在调用Update()
之前执行pIt++
。对返回的原始对象调用Update()
:
for (auto pIt = this->particles.begin(); pIt != this->particles.end(); ) {
auto pForCall = *(pIt++);
pForCall->Update(system, gameTime);
}
另一种不起作用的情况是,被删除的元素不是我们调用的Update
元素。这听起来像是从多个线程并发访问?在这种情况下,您需要使用互斥锁来锁定对列表的访问。请提供一个“否”,多个线程之间不存在并发。这是一个single线程应用程序。事件循环在每一帧上运行。在特定条件下,粒子类会触发被删除。因为它已经在事件循环中使用,所以它会崩溃。如果这一切都在一个线程上,那么不清楚迭代器在这段代码中是如何变得无效的,您需要发布一个mcve@AshutoshRautela向量问题巧妙地。列表的一点是,元素可以在内存中的任何位置更新,这意味着cpu在迭代时可能必须访问每个元素的ram。列表的迭代速度通常令人惊讶,而且通常非常慢。@George它可以防止迭代器失效。@user463035818显然。可能对OP;)看起来是个不错的解决方案。但是问题是我还有一个函数render这是一个生命周期挂钩,在更新生命周期挂钩之后调用。void Explosion::render(Graphics*Graphics)const{for(auto-pIt=This->particles.begin();pIt!=This->particles.end();pIt++{pIt-->render(Graphics);}所以我不能使用成员迭代器variables@AshutoshRautela不清楚为什么不能使用成员变量。可能是您想在问题中添加这些详细信息和代码。这会有什么帮助?@ashutshrautela It post递增迭代器,返回迭代器递增之前引用的值。WhenUpdate()
然后被调用,即使它删除了位于原始迭代器位置的元素,当前迭代器也不会失效,因此循环不会出现故障OK。但问题是删除不是通过更新函数发生的。它发生在随机时间间隔事件上。基本上,删除代码位于另一个在事件中调用。@ashutshrautela如果该事件是在Update()
内部处理的,则此方法可避免Update()
使循环无效。如果不是,则事件与循环干扰的唯一方式是事件与循环并行运行,在另一个线程或中断中,在这种情况下,您必须同步对列表的访问以避免并发访问。@RemyLebeau您的解决方案肯定解决了删除在更新中的情况,在这种情况下,您将保存当前循环中的迭代器,使其不会失效。我提到的第一个循环是在无限循环中的应用程序中被调用,基本上它是在游戏循环中运行的。粒子以随机间隔死亡,因此死亡粒子在死亡后将从容器中删除。希望我能够更好地解释上下文