我想循环浏览std::map
并根据内容删除项目。如何做到最好?
答案 0 :(得分:96)
如果你有一个符合C ++ 11标准的编译器,这里有一个简单的方法:
std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
if (ShouldDelete(*itr)) {
itr = myMap.erase(itr);
} else {
++itr;
}
}
我们的想法是将迭代器从容器的开头向前移动到最后,检查每一步是否应删除当前的键/值对。如果是这样,我们使用erase
成员函数删除迭代的元素,该函数然后将迭代器返回到映射中的下一个元素。否则,我们会正常推进迭代器。
如果您没有符合C ++ 11标准的编译器,或者您正在使用较旧的代码库,那么事情就会有点棘手。在C ++ 11之前,erase
成员函数不会将迭代器返回到映射中的下一个元素。这意味着为了在迭代时删除元素,您需要使用三部分舞蹈:
erase
。此处显示:
std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
if (ShouldDelete(*itr)) {
std::map<K, V>::iterator toErase = itr;
++itr;
myMap.erase(toErase);
} else {
++itr;
}
}
这个过程是必需的,因为如果你只是在迭代器上调用erase
,那么使无效,这意味着增量和减量等操作会导致未定义的行为。上面的代码通过设置迭代器的副本,推进itr
以便它在下一个元素,然后擦除迭代器的临时副本来解决这个问题。
使用一些Clever Trickiness,可以以牺牲可读性为代价缩小此代码。以下模式在较旧的C ++代码中很常见,但在C ++ 11中不是必需的:
std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
if (ShouldDelete(*itr)) {
myMap.erase(itr++); // <--- Note the post-increment!
} else {
++itr;
}
}
这里使用后增量运算符是一种巧妙的方法来制作旧迭代器的副本(记住postfix ++运算符返回原始迭代器值的副本),同时也推进旧的迭代器。
答案 1 :(得分:8)
for(MyMap::iterator it = mymap.begin(); it!=mymap.end(); ) {
if(mycondition(it))
it = mymap.erase(it);
else
it++;
}
编辑:似乎这只适用于MSVC
edit2:在c ++ 0x中,这也适用于关联容器
答案 2 :(得分:7)
这是一个简单的方法:
int value_to_delete( 2 );
for( std::map<int, int>::iterator i = mm.begin(); i != mm.end(); ) {
if( i->second != value_to_delete ) {
mm.erase( i++ ); // advance before iterator become invalid
}
else {
++i;
}
}