在基于范围的for循环中获取无效引用

时间:2015-04-10 21:56:57

标签: c++ c++11 for-loop

auto& kphist = this->kphist;
for (auto& it : kphist) {

    it.second.aging(); // EXC-BAD-ACCESS
    if(it.second.age > LAST_DAY){
        kphist.erase(it.first);
        continue;
    }

}

kphist是私人会员

Class A{
private:
    unordered_map<int, KeyPointHistory> kphist;
} 

调试器显示kphist中的所有项都有效,如何在for循环中有一个错误的引用。什么可能出错?

3 个答案:

答案 0 :(得分:4)

cppreference.com for std::unordered_map::erase()对已擦除元素的引用和迭代器无效。其他迭代器和引用不会失效。因此,您不能在一个范围内使用std::unordered_map::erase() for循环(因为这将尝试增加无效的迭代器)。

为了避免递增无效的迭代器,您可以先简单地递增 然后使用原始迭代器擦除:

for(auto i=map.begin(),end=map.end(); i!=end; ) { // no increment here
  auto it=i++;                                    // but here instead
  if(must_remove(it))
    map.erase(it);
}

实际上,由于erase()将迭代器返回到下一个元素,因此可以避免使用额外的迭代器it(感谢Hurkyl将其指向注释中):

for(auto i=map.begin(),end=map.end(); i!=end; ) { // no increment here
  if(must_remove(i))
    i = map.erase(i);                             // but here 
  else
    ++i;                                          //  or here instead
}

无需列出要删除的元素的键列表......

顺便说一下,为什么不使用std::map(而不是std::unordered_map),因为您的密钥是int(可以轻松订购)?另外,为什么要创建同名成员变量的引用kphist

答案 1 :(得分:2)

迭代时不能删除内容/迭代器,你也不能。

将元素索引保存在另一个容器中,当你完成循环并删除你得到的元素时。

  

可能出现什么问题?

一切!

答案 2 :(得分:0)

您可以通过直接将迭代器传递给要删除的项目来从unordered_map中删除。执行此操作时,erase()将返回后续迭代器,因此您可以执行以下操作:

for (auto pos = kphist.begin(); pos != kphist.end(); ) {
       it.second.aging();
       if(it.second.age > LAST_DAY)
           pos = kphist.erase(it); 
       else
           ++pos;
}

作为奖励,这可能比传递要擦除的密钥快一点 - 因为你提供了迭代器,它可以直接擦除项目而不是重新散列要查找的密钥你已经知道的位置。