我想std::map
根据内容循环并删除项目。这将如何做到最好?
user542687
问问题
90824 次
3 回答
112
如果你有一个兼容 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
使其位于下一个元素处,然后擦除迭代器的临时副本。
使用一些巧妙的技巧,可以以牺牲可读性为代价来缩小此代码。以下模式在较旧的 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;
}
}
此处使用后自增运算符是制作旧迭代器副本的一种巧妙方法(请记住,后缀 ++ 运算符返回原始迭代器值的副本),同时也推进旧迭代器。
于 2011-01-05T03:31:05.673 回答
8
for(MyMap::iterator it = mymap.begin(); it!=mymap.end(); ) {
if(mycondition(it))
it = mymap.erase(it);
else
it++;
}
编辑:似乎这仅适用于 MSVC
edit2:在 c++0x 中,这也适用于关联容器
于 2011-01-05T03:35:16.180 回答
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;
}
}
于 2011-01-05T03:34:04.420 回答