C++ 擦除期间标准容器迭代器失效
可能的重复项:C++ 擦除期间标准容器迭代器失效,c++,g++,std,composite-component,C++,G++,Std,Composite Component,可能的重复项: 我对我的一段代码感到担忧。我有组件和一个存储组件的对象。问题是在更新期间,组件可以告知从对象中删除组件。但它是从另一个函数调用的 void Object::update() { //using std::map here for(ComponentMap::iterator i = components.begin(); i != components.end(); ++i) { (*i).second->update(); } } void
我对我的一段代码感到担忧。我有组件和一个存储组件的对象。问题是在更新期间,组件可以告知从对象中删除组件。但它是从另一个函数调用的
void Object::update() { //using std::map here
for(ComponentMap::iterator i = components.begin(); i != components.end(); ++i) {
(*i).second->update();
}
}
void HealthComponent::update() {
if(health <= 0) object->removeComponent("AliveComponent"); //this is wrong logic. but its just an example :D
}
void Object::removeComponent(string component) {
ComponentMap::iterator i = components.find(component);
if(i == components.end()) return;
components.erase(i);
}
void Object::update(){//在此处使用std::map
对于(ComponentMap::迭代器i=components.begin();i!=components.end();++i){
(*i.second->update();
}
}
void HealthComponent::update(){
if(health removeComponent(“AliveComponent”);//这是错误的逻辑。但它只是一个示例:D
}
void对象::removeComponent(字符串组件){
ComponentMap::迭代器i=components.find(component);
if(i==components.end())返回;
组件。删除(i);
}
假设我有很多组件——健康、活动、图形、物理、输入等等
我尝试了类似的方法(使用了一些测试组件),但在更新过程中没有出现错误。但我真的很担心。它将来会给我弹出一个错误吗?如果是,如何修复它
提前感谢,Gasim当
i
可能不再有效时(因为您删除了它),您不能在容器中循环并说++i
。典型的擦除循环如下所示:
for (it = x.begin(); it != x.end(); /* nothing here! */)
{
if (must_erase(*it))
{
x.erase(it++); // advance it while still valid, return previous and erase
}
else
{
++it;
}
}
以这种精神重写代码
要详细说明您的问题,请在
Object::update()
中调用HealthComponent::update()
使迭代器i
无效,然后调用++i
,这是未定义的行为。在MSVC erase中将返回下一个有效迭代器,但在GCC中它返回void,因此处理此问题的唯一可移植方法是保留上一个迭代器,删除当前元素,然后增加上一个元素下一次迭代的迭代器
@肯:所有版本的
erase
都会将迭代器返回到下一个元素吗?很确定set
不会返回迭代器,因此我的语法不够优雅。(虽然我猜OP使用member-find
意味着它是一个std::list
)很抱歉,你是对的。序列支持这种语法(实际上需要它),但关联容器不支持它。关联容器支持find
,但序列容器不支持。对于这些容器,人们希望使用免费函数std::find
@Ken:不用担心。我还对find
感到困惑,我把它与排序
混淆了(对于它,list
有一个特殊的成员)。如前所述,OP似乎使用了一个关联容器。很高兴我们解决了这个问题:-)我真的很喜欢这个想法。我要发送一个状态,它被擦除或类似的东西。std::find是线性复杂度,因为它覆盖了所有元素。但是集合和映射是排序和平衡的二叉树,所以搜索复杂度是对数的。这就是为什么它有自己的查找函数。我不记得我在哪里看到过这个但是我已经读到,对于关联树,永远不要使用std::find,因为它具有更好的函数。在您的示例代码中,看起来您将删除一个元素,而该元素不一定是Object::update()的元素
目前正在执行。这是一个更困难的问题,如果你真的想这样做,可能需要重新考虑你的设计。@karlphillip:这不是“向量擦除迭代器”的重复,但这可能是另一个问题的重复。正如我刚刚发现的,序列上的erase
与关联容器上的erase
的工作方式不同。您好。有趣的是,我使用的是GCC,并且得到了正确的输出。:/I将看看我能做些什么。谢谢。
void Object::removeComponent(string component, ComponentMap::iterator& _prev )
{
ComponentMap::iterator i = components.find(component);
if(i == components.end())
return;
_prev = i;
--_prev;
components.erase(i);
++prev;
}