迭代std :: multimap并删除某些条目

muf*_*fel 1 c++ std c++11

我想迭代一个std::multimap(所有键的所有值)中的所有项,并删除满足某些条件的所有条目:

#include <map>

typedef int KEY_TYPE;
typedef int VAL_TYPE;

bool shouldRemove(const KEY_TYPE&, const VAL_TYPE&);

void removeFromMap(std::multimap<KEY_TYPE,VAL_TYPE>& map){
    for (auto it = map.begin(); it != map.end(); it++){
        if (shouldRemove(it->first,it->second))
            map.erase(it);
    }
}
Run Code Online (Sandbox Code Playgroud)

除非删除第一个项目,否则迭代会起作用,然后抛出以下错误:

map/set iterator不可递增

removeFromMap为了正常工作,如何重写函数?代码应该适用于地图的各种键和值类型.

我正在使用C++ 11和Visual Studio 2013.

Kar*_*oll 5

在进行擦除之前,需要增加迭代器.当你这样做时map.erase(it);,迭代器it变得无效.但是,地图中的其他迭代器仍然有效.因此,您可以通过在迭代器上执行后递增来解决此问题...

auto it = map.begin();
const auto end = map.end();

while (it != end)
{
    if (shouldRemove(it->first,it->second))
    {
        map.erase(it++);
                 // ^^ Note the increment here.
    }
    else
    {
       ++it;
    }
}
Run Code Online (Sandbox Code Playgroud)

应用于参数it内部的后增量map.erase()将确保it在擦除项之后保持有效,方法是将迭代器递增以指向擦除之前的地图中的下一个项目.

map.erase(it++);
Run Code Online (Sandbox Code Playgroud)

......在功能上等同于......

auto toEraseIterator = it;    // Remember the iterator to the item we want to erase.
++it;                         // Move to the next item in the map.
map.erase(toEraseIterator);   // Erase the item.
Run Code Online (Sandbox Code Playgroud)

正如@imbtfab在评论中指出的那样,你也可以it = map.erase(it)在C++ 11中做同样的事情,而不需要后递增.

另请注意,for由于我们手动控制迭代器,因此循环现在已更改为while循环.

另外,如果您希望尽可能使removeFromMap函数尽可能通用,则应考虑使用模板参数并直接传递迭代器,而不是传递对多图的引用.这将允许您使用任何地图样式的容器类型,而不是强制使用multimap.

例如

template <typename Iterator>
void removeFromMap(Iterator it, const Iterator &end){
    ...
}
Run Code Online (Sandbox Code Playgroud)

这也是标准C++ <algorithm>函数如何做到这一点(例如std::sort(...)).

  • 由于这是C++ 11,避免混淆,只需使用`it = map.erase(it);` (2认同)