Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 擦除期间标准容器迭代器失效_C++_G++_Std_Composite Component - Fatal编程技术网

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;
   }