C++地图上的循环没有检测到地图末端的变化

C++ loop on map not detecting change of map`s end

本文关键字:地图 检测 变化 循环 C++      更新时间:2023-10-16

我在循环遍历地图(std::map)时遇到问题。

在我的循环中,有一个对函数的调用,该函数有时(并非总是)擦除同一映射的元素。使用此函数后,有一些代码使用此地图信息中的一些作为输入。

此功能擦除任何元素后,我没有遇到任何问题,除了在擦除地图最后一个元素的独特情况下。

我的循环不明白地图的最后一个元素与它开始运行时不同,并且会尝试对不存在的元素进行操作,从而造成崩溃。

在我看来,对循环描述的 myMap.end() 调用无法使用映射的新 end() 更新自身。

下面列出了代码的相关部分:

for(std::map<int, ConnectionInfo>::iterator kv = myMap.begin(); kv != myMap.end(); ++kv) {
        int thisConnectionID=kv->first; //This is where I get garbage when the loop enters when it shouldnt;
        ConnectionInfo currentConnectionInfo=kv->second; //This is where I get garbage when the loop enters when it shouldnt;
        status=eraseSomeMapElementsIfNecessary(thisConnectionID,currentConnectionInfo.DownPacket); //this function might erase elements on myMap. This generates no problems afterwards, except when the end element of myMap is erased
        ... //Next parts of the code make no further usage of myMaps, so I just hid it not to pollute the code
}

我的解释是kv != myMap.end()无法理解内部循环正在更改(擦除)myMap 的最后一个元素(结束)吗?

在这种情况下,如何解决此问题?

还是我的解释是错误的,解决方案与我之前所说的无关?

感谢您的帮助!

使用可能删除元素迭代映射时的常用习惯用语是:

for(auto it = map.begin(); it != map.end(); ) {
   if ( *it == /*is to delete*/ ) {
     it = map.erase(it);
   }
   else
     ++it;
}

如果您的擦除某些地图元素如果必要可能会擦除正在迭代的地图中的一些随机值,那么这肯定会引起问题。如果it引用的元素被擦除,则该元素将变为无效,则it递增++it也是无效的。

问题实际上只在于it迭代器,如果擦除SomeMapElementsIfNecessary擦除它然后使用它 - 你有未定义的行为(UB)。因此,解决方案是传递当前迭代器以擦除SomeMapElementsIfNeed,并从中返回下一个迭代器以进行迭代:

it = eraseSomeMapElementsIfNecessary(it);

我示例中的 for 循环的主体应该在您的 eraseSomeMapElementsIf Required 函数中。至少这是一个解决方案。

此功能擦除任何元素后,我没有遇到任何问题,除了在擦除地图最后一个元素的独特情况下。

擦除任何容器中的元素都会使该元素的迭代器失效。之后,递增无效的迭代器。

在删除迭代器所指向的元素之前,应递增迭代器。

如果您不知道在循环中运行的哪些元素会擦除,则假定所有迭代器都无效。

也许这两个链接会有所帮助:

  • 如何使用迭代器删除 std::map 的元素?
  • https://stackoverflow.com/a/8234813/3464942

基本上,这一切都归结为,您必须在迭代器失效之前对其进行更新。

在擦除当前迭代器之前,您必须保留下一个迭代器;因为删除元素后当前迭代器将无效。

auto nextit = it+1;
map.erase(it);
it = nextit;