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

时间:2014-06-10 13:10:12

标签: c++ c++11 std

我想迭代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);
    }
}

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

  

map / set iterator not incrementable

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

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

1 个答案:

答案 0 :(得分: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;
    }
}

it参数中应用map.erase()的后增量将通过递增迭代器以指向地图中的下一个项目来确保it在项目被删除后仍然有效就在擦除之前。

map.erase(it++);

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

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.

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

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

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

e.g。

template <typename Iterator>
void removeFromMap(Iterator it, const Iterator &end){
    ...
}

标准C ++ <algorithm>函数也是这样做的(例如std::sort(...))。