这篇文章将为大家详细讲解有关C++错误的map删除操作和STL中容器的迭代器的底层实现机制,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
成都创新互联公司始终坚持【策划先行,效果至上】的经营理念,通过多达10多年累计超上千家客户的网站建设总结了一套系统有效的全网整合营销推广解决方案,现已广泛运用于各行各业的客户,其中包括:白乌鱼等企业,备受客户表扬。
1.错误的map删除操作
假设有个map容器,用于存储大学班级中各个家乡省份对应的学生数,key为省份中文全拼,value为学生数。现需要删除人数为0的记录,删除代码如下:
map countMap;for(map::iterator it=countMap.begin();it!=countMap.end();++it)
{if(it->second==0)
{
countMap.erase(it);
}
}
猛一看,没问题,仔细一看,有巨坑,STL容器的删除和插入操作隐藏的陷阱主要有如下两条。
(1)对于节点式容器(map, list, set)元素的删除,插入操作会导致指向该元素的迭代器失效,其他元素迭代器不受影响;
(2)对于顺序式容器(vector,string,deque)元素的删除、插入操作会导致指向该元素以及后面的元素的迭代器失效。
所以,在删除一个元素的时候,是没有什么问题的。即:
for(map::iterator it=countMap.begin();it!=countMap.end();++it)
{ if(it->second==0)
{
countMap.erase(it); break;
}
}
但是,当删除多个元素时,程序会出现崩溃。原因是通过迭代器删除指定的元素时,指向那个元素的迭代器将失效,如果再次对失效的迭代器进行++操作,则会带来未定义行为,程序崩溃。解决方法有二,还是以上面的map容器为例,示例删除操作的正确实现:
方法一:当删除特定值的元素时,删除元素前保存当前被删除元素的下一个元素的迭代器。
map::iterator nextIt=countMap.begin();for(map::iterator it=countMap.begin();;)
{ if(nextIt!=countMap.end())
{
++nextIt;
} else
{
break;
} if(it->second==0)
{
countMap.erase(it);
}
it=nextIt;
}
如何更加简洁的实现该方法呢?下面给出该方法的《Effective STL》一书的具体实现:
for(map::iterator it=countMap.begin();it!=countMap.end();)
{ if(it->second==0)
{
countMap.erase(it++);
} else
{
++it;
}
}
该实现方式利用了后置++操作符的特性,在erase操作之前,迭代器已经指向了下一个元素。
再者map.erase()返回指向紧接着被删除元素的下一个元素的迭代器,所以可以实现如下:
for(map::iterator it=countMap.begin();it!=countMap.end();)
{ if(it->second==0)
{
it=countMap.erase(it);
}
else
{
++it;
}
}
方法二:当删除满足某些条件的元素,可以使用remove_copy_if & swap方法。先通过函数模板remove_copy_if 按照条件拷贝(copy)需要的元素到临时容器中,剩下未被拷贝的元素就相当于被“删除(remove)”了,然后在将两个容器中的元素交换(swap)即可,可以直接调用map的成员函数swap。参考代码:
#include #include #include