这篇文章将为大家详细讲解有关c++错误的地图删除操作和STL中容器的迭代器的底层实现机制,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
1。错误的地图删除操作
假设有个地图容器,用于存储大学班级中各个家乡省份对应的学生数,主要为省份中文全拼,值为学生数。现需要删除人数为0的记录,删除代码如下:
map<字符串,整数比;countMap; (map<字符串,int>:: iterator它=countMap.begin();它!=countMap.end (); + +) {如果(它→第二==0) { countMap.erase(它); } }
猛一看,没问题,仔细一看,有巨坑,STL容器的删除和插入操作隐藏的陷阱主要有如下两条。
(1)对于节点式容器(地图、列表、集)元素的删除,插入操作会导致指向该元素的迭代器失效,其他元素迭代器不受影响;
(2)对于顺序式容器(向量,字符串,双端队列)元素的删除,插入操作会导致指向该元素以及后面的元素的迭代器失效。
所以,在删除一个元素的时候,是没有什么问题的。即:
,(map<字符串,int>:: iterator=countMap.begin();它!=countMap.end (); + +) {如果(它→第二==0) { countMap.erase(它);打破; } }
但是,当删除多个元素时,程序会出现崩溃。原因是通过迭代器删除指定的元素时,指向那个元素的迭代器将失效,如果再次对失效的迭代器进行+ +操作,则会带来未定义行为,程序崩溃。解决方法有二,还是以上面地图的容器为例,示例删除操作的正确实现:
<强>方法一:强>当删除特定值的元素时,删除元素前保存当前被删除元素的下一个元素的迭代器。
map<字符串,int祝辞::iterator nextIt=countMap.begin();为(map<字符串,int>:: iterator=countMap.begin ();。) {如果(nextIt !=countMap.end ()) { + + nextIt; 其他} { 打破; }如果(它→第二==0) { countMap.erase(它); } 它=nextIt; }
如何更加简洁的实现该方法呢?下面给出该方法的《有效STL》一书的具体实现:
,(map<字符串,int>:: iterator=countMap.begin();它!=countMap.end ();) {如果(它→第二==0) { countMap.erase (+ +); 其他} { + +; } }
该实现方式利用了后置+ +操作符的特性,在消除操作之前,迭代器已经指向了下一个元素。
再者map.erase()返回指向紧接着被删除元素的下一个元素的迭代器,所以可以实现如下:
,(map<字符串,int>:: iterator=countMap.begin();它!=countMap.end ();) {如果(它→第二==0) { 它=countMap.erase(它); } 其他的 { + +; } }
<>强方法二:强>当删除满足某些条件的元素,可以使用remove_copy_if,交换方法。先通过函数模板remove_copy_if按照条件拷贝(副本)需要的元素到临时容器中,剩下未被拷贝的元素就相当于被“删除(删除)”了,然后在将两个容器中的元素交换(交换)即可,可以直接调用地图的成员函数交换。参考代码:
# include & lt; iostream> # include & lt; string> # include & lt; map> # include & lt; algorithm> # include & lt; iterator>使用名称空间性病;map<字符串,int>mapCount;//不拷贝的条件bool notCopy (pair<字符串,int>key_value) {返回key_value.second==0; }int main () { mapCount.insert (make_pair (“tanwan", 0)); mapCount.insert (make_pair (“anhui" 1)); mapCount.insert (make_pair (“shanghai", 0)); mapCount.insert (make_pair (“shandong" 1));int> map<字符串;mapCountTemp;//临时地图容器//之所以要用迭代器适配器插件函数模板是因为通过调用插入()成员函数来插入元素,并由用户指定插入位置 mapCount.end remove_copy_if (mapCount.begin()()、隔板(mapCountTemp, mapCountTemp.begin ()), notCopy); mapCount.swap (mapCountTemp);//实现两个容器的交换 cout<& lt; mapCount.size () & lt; & lt; endl;//输出2 cout<& lt; mapCountTemp.size () & lt; & lt; endl;//输出4 (map<字符串,int>:: iterator它=mapCount.begin();它!=mapCount.end (); + +) {cout<& lt;它→first<& lt;““& lt; & lt;它→second<& lt; endl; } }
程序输出结果:
2 4 安徽1 山东1
这种方法的缺点:虽然实现两个地图的交换的时间复杂度是常量级,一般情况下,拷贝带来的时间开销会大于删除指定元素的时间开销,并且临时地图容器也增加了空间的开销。