我想遍历 std::map
并根据其内容删除项目。如何做到最好?
最佳答案
如果您有兼容 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
,你会 invalidate 它,这意味着像递增和递减这样的操作会导致未定义的行为。上面的代码通过设置迭代器的拷贝来解决这个问题,推进 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;
}
}
这里使用后自增运算符是制作旧迭代器拷贝的一种巧妙方法(请记住,后缀++ 运算符返回原始迭代器值的拷贝),同时也推进旧迭代器。
关于c++ - 如何使用迭代器删除 std::map 的元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4600567/