迭代std::multimap并删除某些项

Iterate over std::multimap and delete certain entries

本文关键字:删除 std multimap 迭代      更新时间:2023-10-16

我想遍历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迭代器不可递增

如何重写removeFromMap函数才能正常工作?代码应该适用于map的所有键和值类型。

我使用c++ 11和Visual Studio 2013.

在执行擦除操作之前,需要对迭代器进行自增。当你执行map.erase(it);时,迭代器it就失效了。但是,map中的其他迭代器仍然有效。因此,您可以通过在迭代器上执行后自增操作来修复此问题…

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

map.erase()形参内部对it进行后增操作,通过在擦除前对迭代器进行自增,使其指向映射中的下一项,从而确保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在评论中指出的,你也可以在c++ 11中使用it = map.erase(it)来做同样的事情,而不需要后加。

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

另外,如果你想让你的removeFromMap函数尽可能泛型,你应该考虑使用模板形参并直接传递迭代器,而不是传递对multi-map的引用。这将允许您使用任何映射样式的容器类型,而不是强制传入multimap

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

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