如何从std :: map过滤项目?

我大致有以下代码。 这可以做得更好或更有效率? 也许使用std::remove_if ? 你能移走地图中的物品吗? 我们可以避免使用临时地图吗?

 typedef std::map<Action, What> Actions; static Actions _actions; bool expired(const Actions::value_type &action) { return <something>; } void bar(const Actions::value_type &action) { // do some stuff } void foo() { // loop the actions finding expired items Actions actions; BOOST_FOREACH(Actions::value_type &action, _actions) { if (expired(action)) bar(action); else actions[action.first]=action.second; } } actions.swap(_actions); } 

你可以使用erase(),但我不知道BOOST_FOREACH将如何处理失效的迭代器。 map :: erase的文档指出只有被擦除的迭代器将被无效,其他的应该是OK的。 以下是我将如何重构内部循环:

 Actions::iterator it = _actions.begin(); while (it != _actions.end()) { if (expired(*it)) { bar(*it); Actions::iterator toerase = it; ++it; _actions.erase(toerase); } else ++it; } 

Mark Ransomalgorithm的变体,但不需要临时的。

 for(Actions::iterator it = _actions.begin();it != _actions.end();) { if (expired(*it)) { bar(*it); _actions.erase(it++); // Note the post increment here. // This increments 'it' and returns a copy of // the original 'it' to be used by erase() } else { ++it; // Use Pre-Increment here as it is more effecient // Because no copy of it is required. } } 

如果想法是删除过期的项目,为什么不使用map :: erase ? 这样你只需要删除不再需要的元素,而不是用你想要保留的所有元素来重build整个副本。

这样做的方式是保存指向要删除元素的迭代器,然后在迭代结束后将其全部擦除。

或者,您可以保存您访问的元素,移至下一个元素,然后清除临时元素。 在你的情况下,循环边界会变得混乱,所以你必须自己微调迭代。

根据过期()如何实施,可能还有其他更好的方法。 例如,如果您将时间戳记作为映射关键字(如expired()所暗示的那样),则可以在当前时间戳上执行upper_bound,并且范围[begin(),upper_bound())中的所有元素都需要被处理和删除。

从来没有人似乎知道的东西是擦除返回一个新的,保证是有效的迭代器,当在任何容器上使用。

 Actions::iterator it = _actions.begin(); while (it != _actions.end()) { if (expired(*it)) { bar(*it); it = _actions::erase(it); } else ++it; } 

存储actions.end()在这种情况下可能不是一个好的计划,因为我相信迭代器的稳定性是不能保证的。