STL:循环删除容器中元素的方法和陷阱

【C/C++】STL map中erase的正确用法 STL的map里有一个erase方法用来从一个map中删除掉迭代器指示的结点 如 map<string,string> mapTest; auto it=mapTest.find(key); mapTest.erase(it); 像上面这样只是删除单个节点,map的行为不会出现任何问题 但是当在一个循环里用的时候,往往会被误用,那是因为使用者没有正确理解iterator的概念 像下面这样的一个例子就是错误的写法 for(auto it=mapTest.begin();it!=mapTest.e 阅读详情
 

算法大师Donald Knuth:不成熟的优化是一切恶果的根源(Permature optimization is the root of all evil )。

 

STL中的容器主要是两种:序列式容器和关联式容器。

下面讲到的都是我在开发中曾经遇到过的一些问题,有些例子我做了修改,我想初学STL的人基本都会遇到这些问题。

序列式容器:vector list string等等

关联式容器:set map等

 

1、容器的选择,到底要选什么容器应该根据你的需求和以后的扩展来选,可以参考effective stl上的某个条款,说的很清楚,我就不扯了。


2、怎样正确的删除序列式容器中的数据(循环删除),这里以vevtor为例,至少有两大种方法,STL中任何容器都可以使用迭代器进行元素的遍历,当需要在遍历中删除某些元素时,容器中元素的布局(位置或者排序)会随之改变,当前迭代器所指示的元素也会发生变化,这时继续递增或者递减迭代器进行后续元素的遍历时就要特别小心。容器的元素删除方法很大程度上依赖于操作系统上STL的实现版本,不同的系统和STL版本均有不同的定义,当然我们这里以STL的标准来说明。

自己迭代实现删除:

vector<int>::iterator itVec = vectInt.begin();
// 删除所有值为1022的元素
for ( ; itVec != vectInt.end(); )
{
 // 删除
 if (*itVec == 1022)
  itVec = vectInt.erase(itVect);
 else
  ++itVec;
}

上面是正确的实现,容易犯的错误是在erase后还继续++inVect,这是错误的,vector内部实现erase之后itVect实际上已经指向了下一个元素,你再自增就会跳过一个元素,会引发什么问题就很难说了,如果刚好跳过了最后一个元素,还有可能程序在这个地方崩溃。list也可以用这种方法,同时list还可以用下面的方法,只有一点小改动:

list<int>::iterator itList = listInt.begin();
// 删除所有值为1022的元素
for ( ; itList != listInt.end(); )
{
 // 删除
 if (*itList == 1022)
  listInt.erase(itList++);
 else
  ++itList ;
}

vector不能用上面那种方法是因为vector内部是一块连续的内存,而list则是链表。

 

使用stl算法库中的remove remove_if来进行删除:

调用STL中算法 remove或者remove_if的陷阱,并没有真正的删除(你可以此时调用size方法来验证这一点),然后应该使用erase删除残余数据,remove或者remove_if的实现原理是用后面 未被删除的元素 来覆盖前面 应该被删除的元素。返回值ForwardIterator指向经移除后的最后元素的下一位置。如vector{0,1,2,3,3,4},执行remove(),希望移除所有值为3的元素,结果为{0,1,2,4,3,4},返回值ForwardIterator指向第5个元素。即:
  0 1 2 3 3 4 移除前
  0 1 2 4 3 4 移除后

 

这个方法对于自定义类型要自己实现访函数(函数对象),这里就不举例了。

两类方法的对比,其实后面的方法效率要好,如果数据大,用后面的方法,因为针对vector的话,用后面的方法不会像自己用循环去删除的时候,频繁的拷贝移动内存。


3、关联式容器循环删除

for(iter = map.begin(); iter != map.end();)
{
 if (shouldDelete(*iter))
  map.erase(iter++);
 else
  ++iter;
}

因为关联式容器的erase并不返回下一个元素的迭代器,因此不能用iter = map.erase(iter)这样的表达式(有些版本的STL实现又可以这样写,我建议还是使用 map.erase(iter++)保证移植性)。

关联容器同样也可以用remove等来删除元素。


4、谨慎对待操作STL容器的方法begin end size的优化,常见是将他们提取到循环的外部,如果你执行删除操作,可能导致错误,因为在进行删除操作的时候,容器的end,size很有可能随时变化。list容器的end一直不会变化,但是放在for里面,编译器也会优化。除非你能保证for循环中不会改变容器的大小。


附录:

map使用:

第一种:用insert函数插入pair数据

Map<int, string> mapStudent;

mapStudent.insert(pair<int, string>(1, “student_one”));

my_Map.insert(make_pair("d",4));

 

第二种:用insert函数插入value_type数据

Map<int, string> mapStudent;

mapStudent.insert(map<int, string>::value_type (1, “student_one”));

 

第三种:用数组方式插入数据           

Map<int, string> mapStudent;

mapStudent[1] =  “student_one”;

mapStudent[2] = “student_two”


1.连续内存序列容器(vector,string,deque)
序列容器的erase方法返回值是指向紧接在被删除元素之后的元素的有效迭代器,可以根据这个返回值来安全删除元素。

vector<int> c;
for(vector<int>::iterator it = c.begin(); it != c.end();)
{
if(need_delete())
  it = c.erase(it);
 else
  ++it; 
}

 

2.关联容器(set,multiset,map,multimap)

关联容器的erase方法没有返回值,被删除的迭代器失效,所以删除前必须确保能得到下一个迭代器,可以用“后置递增迭代器”技术。

map<int,int> m;
for(map<int,int>::iterator it = m.begin(); it != m.end();)
{
 if(need_delete()) 
  m.erase(it++);
 else
  ++it;
}

m.erase得到it的一个副本,在erase真正开始之前it已经递增了。

所以erase得到了当前的迭代器,在erase内部工作开始之前it已经++了,正好满足我们的需要。

 

3.非连续内存序列容器(list)

只所以单独列出来是因为以上两种方法对list都适用,可依自己喜好选择。

//////////////////////////////////////////////
了解iterator实现细节。。
Cartographer参数调优指南:如何用Lua配置解决建图漂移问题 本文深入解析Cartographer SLAM系统的Lua参数调优方法,针对建图漂移问题提供完整解决方案。从运动滤波、扫描匹配到多传感器融合,详细讲解关键参数配置技巧,并给出仓库物流和服务机器人等典型场景的优化方案,帮助开发者实现精准建图。 阅读详情

相关推荐

Fiddler抓包实战:5分钟搞定微信公众号历史消息接口分析(附完整Python代码)

本文详细介绍了如何使用Fiddler抓包工具逆向分析微信公众号历史消息接口,并提供完整的Python代码实现。从环境准备、动态参数捕获到商业级采集系统架构设计,全面解析了突破官方接口限制的技术方案,帮助开发者高效获取公众号文章数据。

tree8的博客 326

stl容器在循环遍历中删除元素的方式

在实际的应用中,会碰到需要遍历容器中的元素,并且在判断某些的条件后,将某个元素从容器中清除的场景: #include #include #include #include #include #include template void del(T t, int pos) { // 测试循环遍历中的删除操作 int i = 0; for (typename T::iter

jwybobo2007的博客 3867

(入门向)在Ubuntu22.04.3安装Matlab2021b,以及无法安装在当前目录下的解决办法(见最后)

还有这个/usr/local是只读状态,我试过sudo chmod..去改那个文件的读,结果还是安装不了,我不是这个默认路径,因为它文件夹还是只读,于是我在matlab2021b下创了一个bin,并选上。输入完成后,依次按y,因为里面有三个文件,他会让你确定3次密码,直接yyy跳过即可。你可能会遇到装不下的情况,这个软件占30g,可是你分配给虚拟机就剩10g。,于是我去Downloads下建了一个matlab2021b文件夹,果然好使,3).此时,会提示你输入密码,因为这个rar是有密码的,

harrype的博客 7283

stl容器循环删除元素总结

程序中有一段代码是关于stl循环删除的内容,大体逻辑如下(实际逻辑要复杂的多,不适合用std::remove系列函数): int main(int argc, char **argv) { std::vector&lt;int&gt; vec{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; auto it_vec = vec.begin(); while (it_vec...

flyingshineangel的专栏 794

【OpenCV】手眼标定实战:从原理到calibrateHandEye的完整实现

本文详细解析了机器人视觉中的手眼标定原理与实战,重点介绍了如何使用OpenCV的calibrateHandEye函数实现从数据采集到结果验证的完整流程。文章深入剖析了AX=XB核心方程,区分了眼在手上与眼在手外两种配置,并提供了详细的代码示例与避坑指南,帮助开发者精准建立相机与机械臂末端的坐标转换关系,是机器人精准抓取的关键技术。

weixin_29046611的博客 508

保姆级教程:如何用Le2i Fall Detection Dataset训练你的跌倒检测模型(附数据集下载)

本文提供了一份详细的实战指南,教你如何使用Le2i Fall Detection Dataset训练跌倒检测模型。内容涵盖数据集的深度解析、预处理与工程化管道搭建、模型选择与训练策略,以及评估优化与部署考量,旨在帮助开发者从零构建高精度、可应用的跌倒检测系统。

assembly8low的博客 1287

C++ STL vector list set map容器循环通过迭代器删除元素注意事项

stl中通过迭代器删除vector,list,set,map中的元素

hsy12342611的专栏 5224

PCL 点云圆柱形邻域搜索【2026最新版】

圆柱形邻域搜索是KD-tree算法在点云数据处理中的扩展应用,在一些特定场景应用中具有无与伦比的优势。博客长期更新,本文最近一次更新时间为:2026年5月4日。

点云侠的博客 3450

循环删除List容器中的元素

循环删除List容器中的元素

sspuflk的专栏 1208

智能车图像处理12-进阶篇4--环岛辅助判断条件

主函数: 第6行: 含义是当前需要不在坡道和车库状态 第11-12行 : 寻找一下环岛的双断点(在辅助函数中) 第16-66行: 当左右线的方差满足一边很大,一边很小时,truepianfangflag /truepianfangflagforleft 置1,在环岛的判断中使用。 辅助函数: 双断点函数(左与右相似,以做为例): 第13-28行: 第一处断点 第29-40行: 第一处断点后 连续边线 第41-52行: 第一处连续后,第二处断点 第53-64行: 第二处断点后,第二处

taiyuezyh的博客 1万+

【51单片机实物】基于51单片机设计的简易直流电机调测速系统(可用在普中开发板)

功能任务描述:将设置的转速与当前测量的转速比较,得出差值用于控制DAC0832的输出电压,从而控制直流电机的转速,使转速逐渐达到设置转速。在LED上显示设置转速(左2位LED)和当前转速(右2位LED),转速显示采用十进制。控制过程中,当前转速显示不断变化。*直流电机转速范围0-96r/s,误差±1r/s

嵌入式阿齐Archie 1万+

STL序列式容器中删除元素的方法和陷阱(一)

 在STL(标准模板库)中经常会碰到要删除容器中部分元素的情况,本人在编程中就经常编写这方面的代码,在编码和测试过程中发现在STL中删除容器有很多陷阱,网上也有不少网友提到如何在STL中安全删除元素这些问题。本文将讨论编程过程中最经常使用的两个序列式容器vector、list中安全删除元素的方法和应该注意的问题, 其它如queue、stack等配接器容器(container adapter),由于

Alvin-He的专栏 1084

Altium Designer应用技巧5: Altium Live账号的获得

为了更好的应用Altium Designer,我们需要得到一个Altium Live账号,但从其英文或者中文官方网站取得,都需要7个工作日的时间,而且对于个人用户来说,并不是100%都能够获取到。本文介绍一种,从俄罗斯Altium官方网站获取账号的方法,可以立即使用。     1、点击http://live.altium-ru.com/#Join网址进入俄罗斯Altium官方网站,Altiu

snmplink的博客 1万+

map使用注意事项

STL的map表里有一个erase方法用来从一个map中删除掉指令的节点 eg1: map<string,string> mapTest; typedef map<string,string>::iterator ITER; ITER iter=mapTest.find(key); mapTest.erase(iter); 像上面这样只是删除单个节点,map的形为不...

lili的博客 776

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

STL面试必问的迭代器失效问题:从map.erase()到vector.insert()的避坑指南

本文深入解析C++ STL迭代器失效问题,从底层原理到实战避坑指南,涵盖vector、map等容器的增删操作对迭代器的影响。通过gdb调试示例和面试高频陷阱题破解技巧,帮助开发者掌握安全操作迭代器的方法,避免常见错误。

weixin_30632089的博客 491

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

vector中erase用法注意事项

以前就发现了vector中的erase方法有些诡异(^_^),稍不注意,就会出错。今天又一次遇到了,就索性总结一下,尤其是在循环体中用erase时,由于vector.begin() 和vector.end()是变化的,因此就引入了错误的可能性。 erase的函数原型有两种形式: iterator erase(iterator position); iterator erase(iterato...

xiaobai 465

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

STL中各种容器的删除操作

在应用中,我们通常不可避免地要对容器中的某些特定元素进行删除操作。这看起来并不是什么困难的问题。我们先写一个循环来迭代容器中的元素,如果迭代元素是要删除的元素,则删除之。代码如下所示: vector intContainer; ..... for(vector::iterator is = intContainer.begin(); it != intContainer.e

ACM_10000h的专栏 2945

在for循环中为STL容器插入与删除元素的注意事项

c++11关于for循环的新特性 std::vector<int> A(5, 2); for (auto b : A) { b += 1; } for (auto &b : A) { b += 2; } for (const auto &b : A) { std::cout << b << std::endl; } 三种用途有显著的...

onlytheworld的博客 2295

STL容器删除元素的陷阱

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34216036的博客 119

告别迭代效率陷阱:STL容器的for循环与迭代器深度测评

MSVC's implementation of the C++ Standard Library(以下简称STL)是C++开发中不可或缺的工具库,其容器与迭代器的高效使用直接影响程序性能。本文将深入剖析STL容器在for循环与迭代器使用中的效率差异,帮助开发者避开常见的性能陷阱,提升代码运行速度。 ## 一、STL容器迭代方式对比:从基础到进阶 ### 1.1 传统for循环:简单但暗藏隐患

gitblog_00007的博客 660

转载: STL序列式容器中删除元素的方法和陷阱一 .

  在 STL (标准模板库)中经常会碰到要删除容器中部分元素的情况,本人在编程中就经常编写这方面的代码,在编码和测试过程中发现在 STL 中删除容器有很多陷阱,网上也有不少网友提到如何在 STL 中安全删除元素这些问题。本文将讨论编程过程中最经常使用的两个序列式容器 vector 、 list 中安全删除元素的方法和应该注意的问题,        其它如 queue 、 stack 等配接器...

weixin_34184158的博客 83

STL容器的删除元素问题

STL的容器分为两类,一类是序列式容器,即数据顺序连续存储,如:vector、deque;另一类是关联式容器,即数据不连续存储,如:map、list、set。对于STL容器的数据删除操作,有一些需要注意的地方。 1、序列式容器的数据删除        下面例子以容器list为例: [cpp] view plain copy for (list

weixin_36145588的博客 325

转载: STL序列式容器中删除元素的方法和陷阱二 .

2.使用 STL 中通用算法或容器成员函数删除元素的方法 以上手工编写 for 循环代码删除容器中元素的方法也有一些问题,如果判断条件特别复杂,又有循环判断的话,循环中间又有异常处理的话, ++itVect 的位置就要小心放置了,稍不留意就要出错。所以手工编写代码删除容器中元素的方法不太安全,代码重复,也不够优雅,要注意的地方很多。 对于这种情况,可以考虑使用 STL 中通用算法 remvoe...

weixin_34408624的博客 95

STL容器erase的使用陷阱

原文:http://blog.youkuaiyun.com/waterathena/article/details/2943715在STL(标准模板库)中经常会碰到要删除容器中部分元素的情况,本人在编程中就经常编写这方面的代码,在编码和测试过程中发现在STL中删除容器有很多陷阱,网上也有不少网友提到如何在STL中安全删除元素这些问题。本文将讨论编程过程中最经常使用的两个序列式容器vector、l...

diche7031的博客 239

STL序列式容器中删除元素的方法和陷阱 一

STL序列式容器中删除元素的方法和陷阱 一 在STL(标准模板库)中经常会碰到要删除容器中部分元素的情况,本人在编程中就经常编写这方面的代码,在编码和测试过程中发现在STL中删除容器有很多陷阱,网上也有不少网友提到如何在STL中安全删除元素这些问题。本文将讨论编程过程中最经常使用的两个序列式容器vector、list中安全删除元素的方法和应该注意的问题,       其它如queue、st

hurtmanzc的专栏 1131
上一篇: 内存地址对齐
下一篇: C语言逗号运算符和逗号表达式
wang37921
博客等级 码龄18年 14粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值