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

Alv*_*var 0 c++ for-loop c++11

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

}
Run Code Online (Sandbox Code Playgroud)

kphist 是私人成员

Class A{
private:
    unordered_map<int, KeyPointHistory> kphist;
} 
Run Code Online (Sandbox Code Playgroud)

调试器显示 kphist 中的所有项目都是有效的,怎么可能在 for 循环内有错误的引用。可能会出现什么问题?

Wal*_*ter 5

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

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

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);
}
Run Code Online (Sandbox Code Playgroud)

事实上,由于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
}
Run Code Online (Sandbox Code Playgroud)

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

顺便说一句,为什么你不使用 a std::map(而不是 an std::unordered_map),因为你的密钥是 an int(很容易订购)?另外,为什么要引用kphist同名的成员变量呢?