我如何从一个地图,而迭代它?如:
std::map<K, V> map;
for(auto i : map)
if(needs_removing(i))
// remove it from the map
如果我用地图。擦除它将使迭代器失效
我如何从一个地图,而迭代它?如:
std::map<K, V> map;
for(auto i : map)
if(needs_removing(i))
// remove it from the map
如果我用地图。擦除它将使迭代器失效
当前回答
很伤心,是吧?我通常的做法是建立一个迭代器容器,而不是在遍历过程中删除。然后遍历容器并使用map.erase()
std::map<K,V> map;
std::list< std::map<K,V>::iterator > iteratorList;
for(auto i : map ){
if ( needs_removing(i)){
iteratorList.push_back(i);
}
}
for(auto i : iteratorList){
map.erase(*i)
}
其他回答
c++ 20草案包含了方便函数std::erase_if。
你可以用这个函数来做一行代码。
std::map<K, V> map_obj;
//calls needs_removing for each element and erases it, if true was reuturned
std::erase_if(map_obj,needs_removing);
//if you need to pass only part of the key/value pair
std::erase_if(map_obj,[](auto& kv){return needs_removing(kv.first);});
很伤心,是吧?我通常的做法是建立一个迭代器容器,而不是在遍历过程中删除。然后遍历容器并使用map.erase()
std::map<K,V> map;
std::list< std::map<K,V>::iterator > iteratorList;
for(auto i : map ){
if ( needs_removing(i)){
iteratorList.push_back(i);
}
}
for(auto i : iteratorList){
map.erase(*i)
}
标准的关联容器擦除习惯用法:
for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */)
{
if (must_delete)
{
m.erase(it++); // or "it = m.erase(it)" since C++11
}
else
{
++it;
}
}
注意,这里我们实际上需要一个普通的for循环,因为我们正在修改容器本身。基于范围的循环应该严格保留在只关心元素的情况下。RBFL的语法甚至没有公开循环体中的容器,这一点很清楚。
编辑。在c++ 11之前,你不能擦除常量迭代器。你可能会说:
for (std::map<K,V>::iterator it = m.begin(); it != m.end(); ) { /* ... */ }
从容器中删除一个元素与元素的常量性并不矛盾。通过类比,当p是指向常量的指针时,删除p总是完全合法的。刚毅并不束缚一生;c++中的const值仍然可以停止存在。
假设c++ 11,这里是一行循环体,如果这与你的编程风格一致的话:
using Map = std::map<K,V>;
Map map;
// Erase members that satisfy needs_removing(itr)
for (Map::const_iterator itr = map.cbegin() ; itr != map.cend() ; )
itr = needs_removing(itr) ? map.erase(itr) : std::next(itr);
其他一些较小的风格变化:
在可能/方便的时候显示声明的类型(Map::const_iterator),而不是使用auto。 对模板类型使用using,使辅助类型(Map::const_iterator)更易于阅读/维护。
我个人更喜欢这种模式,它更清晰更简单,但牺牲了一个额外的变量:
for (auto it = m.cbegin(), next_it = it; it != m.cend(); it = next_it)
{
++next_it;
if (must_delete)
{
m.erase(it);
}
}
这种方法的优点:
for循环的增量器作为增量器是有意义的; 擦除操作是简单的擦除,而不是与增量逻辑混合在一起; 在循环体的第一行之后,it和next_it的含义在整个迭代过程中保持固定,允许您轻松添加引用它们的其他语句,而不必担心它们是否会像预期的那样工作(当然,除了在删除它之后不能使用它)。