地图上的C++循环没有检测到地图结束的变化

use*_*682 4 c++ containers dictionary iterator loops

我在循环通过地图时遇到问题(std :: map).

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

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

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

在我看来,对循环描述的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
}
Run Code Online (Sandbox Code Playgroud)

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

在这种情况下,我该如何解决这个问题?

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

谢谢你的帮助!

mar*_*inj 6

迭代具有可能删除元素的地图时通常的习惯用法是:

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

如果你的eraseSomeMapElementsIfNecessary可能会删除迭代的map中的一些随机值,那么这肯定会导致问题.如果元素,其it被引用得一干二净,就变成无效,然后递增it++it也无效.

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

it = eraseSomeMapElementsIfNecessary(it);
Run Code Online (Sandbox Code Playgroud)

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

  • ad1)你必须将上面的地图与擦除迭代习语放在你的eraseSomeMapElementsIfNecessary函数中.我已经给出了一个提示如何做到这一点. (2认同)