别被vector最后一个元素erase错误

作者: 良知犹存

​{cke_bm_165S}

前言:

vector们经常使用,对vector里面的基本函数构造函数、增加函数、删除函数、遍历函数们也会用到。其中在使用遍历之后erase删除元素过程中,会出现一种删除最后一个元素破坏了迭代器的情况。

如下所示 删除到最后一个元素的时候就会报错

vector<int> data(10);
auto temp_begin = data.begin(), temp_end= data.end();
for(;temp_begin!=temp_end;){
    data.erase(temp_begin);
}

产生这个问题的原因是:当们调用erase方法删除元素的时候,erase方法会返回下一个元素的迭代器。当删除到最后一个元素的时候,这个时候返回的是最后一个元素之后的容器,而不是最后一个元素。

作者:良知犹存

转载授权以及围观:欢迎关注微信公众号:羽林君

或者添加作者个人微信:become_me


原因分析:

vector:

Because vectors keep an array format, erasing on positions other than the vector end also moves all the elements after the segment erased to their new positions, which may not be a method as efficient as erasing in other kinds of sequence containers (deque, list). This invalidates all iterator and references to position (or first) and its subsequent elements.

假设你的 vector 中有多个对象,最后一个被标记为销毁。当您调用erase时,它将返回一个新的有效迭代器,该迭代器指向已删除元素之后的元素。被删除的元素之后没有元素,因此返回的迭代器为data.end()。

然后,们继续循环的顶部并取消引用此迭代器,这是无效的。如果要让迭代器指向有效元素,则需要在擦除后减少其迭代器。vec.end() 给你元素的迭代器以下容器的最后一个元素。看这里:

list和vector区别(list 这样删除就没事)

List:

This effectively reduces the list size by the number of elements removed, calling each element's destructor before.

lists are sequence containers specifically designed to be efficient inserting and removing elements in any position, even in the middle of the sequence. Compared to the other base sequence containers (vector and deque), lists are the most efficient container erasing at some position other than the beginning or the end of the sequence, and, unlike in these, all of the previously obtained iterators and references remain valid after the erasing operation and refer to the same elements they were referring before (except, naturally, for those referring to erased elements).

列表是序列容器,专门设计用于在任何位置高效插入和删除元素,甚至在序列的中间。list erase不会改变原来的iterator,所以不会出现像vector删除最后一个iterator后程序错误。

修改建议

下面修改的建议都是让vector的end迭代器可以一直更新,重新判断当前位置。

vector<int> data(10);
auto iter = data.begin();
while(iter != data.end())
{
  data.erase(iter);
}


for (iter = data.begin(); it != data.end();)
{
    data.erase(iter);
}

将删除最后一个元素

data.erase(data.end() - 1); 


 data.erase(data.begin() + data.size() - 1); 

应该提到的是,如果向量为空,则该操作将崩溃,因此出于安全考虑,们可以再添加一个vector是否为空的判断

if (!data.empty())
  data.erase(vec.end() - 1);

另外们也发现 vector 的 erase 需要整个vector 移动,这个代价十分高,所以尽量少用。若排序顺序不是很重要的话,可以和最后的那个item swap,然后删掉最后那个,这样可以显著的提高效率。

结语

这就是分享的项目中一些vector使用,如果大家有更好的想法和需求,也欢迎大家加好友交流分享哈。


作者:良知犹存,白天努力工作,晚上原创公号号主。公众号内容除了技术还有些人生感悟,一个认真输出内容的职场老司机,也是一个技术之外丰富生活的人,摄影、音乐 and 篮球。关注,与一起同行。

                                                ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

推荐阅读

【1】C++的智能指针你了解吗?

【2】嵌入式底层开发的软件框架简述

【3】CPU中的程序是怎么运行起来的 必读

【4】cartographer环境建立以及建图测试

【5】设计模式之简单工厂模式、工厂模式、抽象工厂模式的对比

本公众号全部原创干货已整理成一个目录,回复[ 资源 ]即可获得。


原文作者:良知犹存

原文链接:https://www.cnblogs.com/conscience-remain/p/15389459.html

更多推荐

更多
  • Java开发常见错误100例-29数据和代码:数据就是数据,代码就是代码 29 数据和代码:数据就是数据,代码就是代码 今天,我来和你聊聊数据和代码的问题。 正如这一讲标题"数据就是数据方面的很多漏洞,都是源自把数据当成了代码来执行,也就是注入类问题,比如: 客户端提供给服务端的查询值,是一个数据,会
  • Java开发常见错误100例-33加餐3:定位应用问题,排错套路很重要 33 加餐3:定位应用问题,排错套路很重要 咱们这个课程已经更新 13 讲了,感谢各位同学一直在坚持学习,并在评论区留下了很多高质量,有的是分享自己曾经踩的坑,有的是对课后思考题的详细解答,还有的是提出了非常好的问题,进一步丰富了这
  • Java开发常见错误100例-36加餐6:这15年来,我是如何在工作中学习技术和英语的? 36 加餐6:这15年来,我是如何在工作中学习技术和英语的? 今天,我来和你聊聊如何在工作中,让自己成长得更快。 工作这些年来,经常会有同学来找我沟通学习和成长,他们的问题可以归结为沟通学习和成长,他们的问题可以归结为两个。 一
  • Java开发常见错误100例-16用好Java8的日期时间类,少踩一些“老三样”的坑 16 用好Java 8的日期时间类,少踩一些"老三样"的坑 今天,我来和你说说恼人的时间错乱问题。 在,使用 Date、Calender 和 SimpleDateFormat,来声明时间戳、使用日历处理日期和格式化解析日期时间。但
  • Java开发常见错误100例-答疑篇:代码篇思考题集锦(一) 答疑篇:代码篇思考题集锦(一)题的答案。因此呢,我特地将这个课程涉及的思考题进行了梳理,把其中的 67 个问题的答案或者说解题思路,详细地写了出来,并整理成了一个"答疑篇"模块。 我把这些问题拆分为了 6 篇分别更新,你可以根据自己的
  • Java开发常见错误100例-30如何正确保存和传输敏感数据? 30 如何正确保存和传输敏感数据? 今天,我们从安全角度来聊聊用户名、密码、身份证等敏的散列、对称加密和非对称加密算法,以及 HTTPS 等相关知识。 应该怎样保存用户密码? - 最敏感的数据恐怕就是用户的密
  • Java开发常见错误100例-15序列化:一来一回你还是原来的你吗? 15 序列化:一来一回你还是原来的你吗? 今天,我来和你聊聊序列化相关的坑和最佳实践。 序列化是把对象转换为字节流的过程,以方便传输或存储。反序列化,则是反过来把字节流转换为对象化,则是反过来把字节流转换为对象的过程。在介绍文件
  • Java开发常见错误100例-23缓存设计:缓存可以锦上添花也可以落井下石 23 缓存设计:缓存可以锦上添花也可以落井下石 今天,我从设计的角度,与你聊聊缓存。 通常我们会使用更快的介质(比如内存)作(比如磁盘)读取数据慢的问题,缓存是用空间换时间,来解决性能问题的一种架构设计模式。更重要的是,磁盘上存储
  • Java开发常见错误100例-17别以为“自动挡”就不可能出现OOM 17 别以为"自动挡"就不可能出现OOM 今天,我要和你分享的主题是,别以为"自动挡"就不可能出现 OOM。 这里的"自动挡",是我自动垃圾收集器的戏称。的确,经过这么多年的发展,Java 的垃圾收集器已经非常成熟了。有了自动垃圾
  • Java开发常见错误100例-结束语写代码时,如何才能尽量避免踩坑? 结束语 写代码时,如何才能尽量避免踩坑? -余时间都用了在这个课程的创作,以及回答你的问题上,很累很辛苦,但是看到你的认真学习和对课程内容的好评,看到你不仅收获了知识还燃起了钻研源码的热情,我也非常高兴,深觉一切的辛苦付出都是甜蜜的。
  • 近期文章

    更多
    文章目录

      推荐作者

      更多