尝试增加std :: map迭代器时的SIGBUS

时间:2017-12-07 16:28:28

标签: c++ c++98

我正在调试一个大的 C ++ 98 应用程序,当方法尝试增加SIBGUS时,我收到std::map::iterator错误。

通过填充跟踪,我发现有问题的方法从提到的地图中删除元素(indireclty,通过调用其他方法调用其他方法等等),所以我怀疑问题是在删除其元素时迭代地图

我一直在寻找正确的方法来迭代std::map并删除项目safelly,我发现了这个:

for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */)
{
  if (must_delete)
  {
    m.erase(it++);    // or "it = m.erase(it)" since C++11
  }
  else
  {
    ++it;
  }
}

引自 How to remove from a map while iterating it?

的代码

我对此有一些疑问:

实际上是否有必要区分是否删除元素,考虑到迭代器在任何情况下都会增加?

以下代码片段在安全方面是否等同于上述代码片段?

for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */)
{
  if (must_delete)
  {
    m.erase(it);
  }
  it++;
}

生成SIGBUS的方法遵循以下模式:

std::map<..., ...>::iterator it = myMap.begin(); // myMap is an instance attribute and can be accessed by any class method.

while(it != myMap.end() {
  if(somethingHappens())
    doSomethingThatMightDeleteMapElements(); // this can (or not) delete 'myMap' elements.
  it++; // The error occurs here
}

由于删除是由其他方法执行的,我无法区分是否已删除某个元素(除非我返回一个布尔值或类似值)。 这可能不安全吗?

2 个答案:

答案 0 :(得分:2)

  

以下代码片段在安全方面是否等同于上述代码片段?

不,当然不是,在将it传递给map.erase()后,由于该调用使迭代器无效,因此无法增加 map.erase(it++); 。区别在于:

iterator tmp = it;
++it;
map.erase( tmp );

在逻辑上等同于:

tmp

因此,在这种情况下,it无效,但while(it != myMap.end() { if(somethingHappens()) doSomethingThatMightDeleteMapElements(); // this can (or not) delete 'myMap' elements. it++; // The error occurs here } 仍然有效。

考虑此代码:

while(it != myMap.end() {
  if(somethingHappens()) {
    key_type key = it->first();
    doSomethingThatMightDeleteMapElements(); // this can (or not) delete          'myMap' elements.
    it = myMap.upper_bound( key );
  } else
     it++;
}

我认为唯一可行的方法是:

{{1}}

答案 1 :(得分:0)

  

由于删除是由其他方法执行的,我无法区分是否删除了一个元素(除非我返回一个布尔值或类似的)。

你当然可以。在调用doSomethingThatMightDeleteMapElements之前保持地图的大小。调用doSomethingThatMightDeleteMapElements后获取地图的大小。然后根据它们是否相等采取适当的行动。

while(it != myMap.end() {
  size_t size_before = myMap.size();
  size_t size_after = size_before;
  if(somethingHappens())
  {
    doSomethingThatMightDeleteMapElements(); // this can (or not) delete myMap  elements.
    size_after = myMap.size();
  }

  if ( size_before != size_after )
  {
    // Be safe. Iterate from the start again.
    it = myMap.begin();
  }
  else
  {
    it++; // The error occurs here
  }
}