3

可能的重复:
向量擦除迭代
器在调用擦除()后出现 std::map::iterator 问题


我对我拥有的一段代码感到担忧。我有组件和一个存储组件的对象。问题是在更新期间组件可以告诉从对象中删除组件。但它是从另一个函数调用的。

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

}

假设我有很多组件——健康、活着、图形、物理、输入等。

我尝试了这样的事情(使用一些测试组件)并且在更新期间没有错误。但我真的很担心。它可以在将来弹出我的错误吗?如果是,如何解决?

提前致谢,
加西姆

4

2 回答 2

7

您不能遍历您的容器并说出++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,这是未定义的行为。

于 2011-06-26T21:46:17.157 回答
1

在 MSVC 中擦除将返回下一个有效迭代器,但在 GCC 中它返回 void,因此处理此问题的唯一可移植方法是保留前一个迭代器,擦除当前元素,然后为下一次迭代递增前一个迭代器。

http://www.cplusplus.com/reference/stl/map/erase/

  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;
   }
于 2011-06-26T22:26:09.790 回答