删除C++STL多映射中特定键的条目
Removing entries of particular key in C++ STL multimap
我有这个示例代码来向多映射插入条目。我正在尝试删除指定密钥的特定条目。但这段代码进入了无限循环。有人能帮我处理这个代码吗?
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
multimap<string, string> names;
string n;
names.insert(pair<string, string>("Z", "F"));
names.insert(pair<string, string>("Z", "A"));
names.insert(pair<string, string>("S", "T"));
names.insert(pair<string, string>("S", "A"));
names.insert(pair<string, string>("S", "J"));
names.insert(pair<string, string>("D", "H"));
names.insert(pair<string, string>("D", "W"));
names.insert(pair<string, string>("D", "R"));
multimap<string, string>::iterator p;
p = names.find("Z");
if(p != names.end()) { // found a name
do {
cout << n << ", " << p->second;
cout << endl;
if (p->second.compare("A") == 0) {
names.erase(p);
p++;
} else {
p++;
}
} while (p != names.upper_bound("Z"));
}
else{
cout << "Name not found.n";
}
p = names.find("Z");
if(p != names.end()) { // found a name
do {
cout << n << ", " << p->second;
cout << endl;
} while (p != names.upper_bound("Z"));
}
else{
cout << "Name not found.n";
}
return 0;
}
在上面,我正在使用键值"Z"查找,并希望删除"A"。
multimap::erase
使擦除元素的任何迭代器无效,因此行
names.erase(p);
p++;
擦除p,从而使其无效,然后尝试递增一个无效的迭代器。可以通过将p
复制到临时迭代器,递增p,然后擦除临时迭代程序来解决此问题。
multimap<string, string>::iterator temp = p;
++p;
names.erase(temp);
或者,如果您使用C++11,则multimap::erase
返回容器中的下一个迭代器
p = names.erase(p);
编辑:上面并不是你无限循环的来源。在第二个循环中,您不递增p
,因此它将永远存在。然而,它仍然是你应该修复的问题,因为它可能会导致不可预测和难以追踪的错误。
正如其他人所说,推进一个指向刚刚擦除的元素的迭代器并不能保证有效。相反,您可以使用后缀++
运算符来检索元素的迭代器,该元素在被擦除之前位于被擦除的元素之后:
names.erase(p++);
在C++11中,您也可以检索erase
的返回值,它指向以下元素(如果没有更多元素,则为end()
):
p = names.erase(p);
还有人已经说过,根据定义,第二个循环是一个无限循环,因为它从不递增计数器。
然而,还有一件事需要说明:检查元素范围中的最后一个元素是否已到达的方法效率不高:在循环的每次迭代中调用upper_bound
,这将导致每次都进行新的O(log(n))树搜索,尽管返回的迭代器始终相同。
在进入循环并存储结果之前,运行upper_bound
显然可以改善这一点。但更好的是,我建议您运行equal_range
函数一次,然后简单地迭代它返回的范围:
typedef multimap<string,string>::const_iterator mapit;
std::pair<mapit,mapit> range = names.equal_range("Z");
mapit it = range.first;
while (it != range.second)
if (it->second == "A")
names.erase(it++);
else
++it;
在C++11中,auto
的使用将使其看起来更好。
相关文章:
- STL映射比较器能否以某种方式获取指向映射本身的指针?
- 在 c++ stl 映射中,删除具有重复值的条目
- C++ STL 映射同时更新所有值
- 遍历 STL 映射(集/多集)的最佳方法,同时元素可能会在循环期间被删除并重新插入?
- 无法将元素添加到 STL 映射
- 为什么不能在STL映射中插入值
- 在 stl 映射和列表 (c++) 上进行迭代的泛型循环
- 未签名的char数组到stl ::映射或其他容器中的键
- 整数和元组的静态 STL 映射返回 0
- 指向类的指针的 STL 映射的 SWIG 类型图
- 将 STL 映射存储到 Boost ConstBufferSequence 中
- 如何在下一次函数调用中使用 STL 映射擦除从最后一个位置
- 如何使用密钥 2 更新 STL 映射键 1 并将值复制到键 2 中
- 为什么当代码尝试在 STL 映射中查找键时出现分段错误
- 快速插入STL映射
- C STL映射中的SegFault由于过程退出期间的静态可变清理而找到
- 如何将 STL 映射保存到文件C++
- C++STL映射键和值工作不正常
- STL 映射自定义比较器
- 带有内存比较的 STL 映射.如何在运行时设置比较块大小