写点什么

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

用户头像
良知犹存
关注
发布于: 刚刚

前言:

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】设计模式之简单工厂模式、工厂模式、抽象工厂模式的对比


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

发布于: 刚刚阅读数: 2
用户头像

良知犹存

关注

还未添加个人签名 2020.05.29 加入

还未添加个人简介

评论

发布
暂无评论
别被vector最后一个元素erase错误