如果您有兼容 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;
}
}
这里使用后自增运算符是制作旧迭代器副本的一种巧妙方法(请记住,后缀 ++ 运算符返回原始迭代器值的副本),同时也推进旧迭代器。