吃了这玩意的大亏,特此记录!
C++中删除map里的元素需要调用erase操作,但是错误的调用,会导致很多不可预支的问题,甚至于程序运行崩溃,不幸的是,楼主就遇到此情况,两天的Debug,结果发现仅是map删除元素时操作不当的问题!
一、在C++98前,erase操作
删除元素的操作是这样的
void erase (iterator position);
size_type erase (const key_type& k);
void erase (iterator first, iterator last);
用迭代器删除时,返回的是void。
二、在C++11后,的erase操作
就变成如下这样,返回的还是一个迭代器,且指向的删除后的下一个iter
iterator erase (const_iterator position);
size_type erase (const key_type& k);
iterator erase (const_iterator first, const_iterator last);
三、迭代器删除map中某一元素的正确用法
对于关联容器(如map, set, multimap,multiset),删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前iterator即可。
这是因为map之类的容器,使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响。
当然,C++11后,erase(iter)操作会返回下一个迭代器,因此就可以不需要递增了。
#include <iostream>
#include <map>
using namespace std;
int main() {
map<int, string> m{{1, "one"}, {2, "two"},{3, "three"}, {4, "four"}, {5, "five"}};
for(auto iter = m.begin(); iter != m.end();)
{
if (iter->first == 4)
{
iter = m.erase(iter);
}
else
++iter;
}
for(auto iter = m.begin(); iter != m.end(); iter++)
{
std::cout << iter->first <<" " << iter->second << std::endl;
}
std::cout << "Hello, World!" << std::endl;
return 0;
}
四、切记不可使用的方法(错误!错误!错误!)
下面这段看样子貌似非常正常的一 段代码。在一个map中寻找值为xxx的项并删除。但是实际上这个代码是完全错误的,会导致无法预料的结果。
因为对于关联容器(如map, set, multimap,multiset),删除当前的iterator,仅仅会使当前的iterator失效。
如果在不知情的情况下使用了失效的迭代器,后果是不可预料的。可能程序立即崩掉,也可能什么事都没有发生。崩掉了还算幸运,因为至少知道出了问题,不然有的受的。
好吧,博主在开发环境上一切正常,在部署环境上就崩溃了,一度怀疑部署环境有问题。
int main()
{
map<int, string> m{{1, "one"},
{2, "two"},
{3, "three"},
{4, "four"},
{5, "five"},
{6, "three"}};
for(auto iter = m.begin(); iter != m.end(); ++iter)
{
if (iter->second == "four")
{
m.erase(iter);
}
}
for(auto iter = m.begin(); iter != m.end(); iter++)
{
std::cout << iter->first <<" " << iter->second << std::endl;
}
std::cout << "Hello, World!" << std::endl;
return 0;
}