vector的erase函数问题,该函数删除一个元素,是不是把后面的元素前移?

看到机器就疯狂 2013-06-20 10:09:05
会不会导致内存重新分配,有没有这个可能?
或者仅仅是将被删除元素后面的元素前移,如果这个可能被证实,那么为什么还有这样的语句:
v.erase(remove(v.begin(),v.end(),99999),v.end());
既然erase可以将被删除元素后面的元素前移,还要remove来这里忙活什么?
不好意思,问题有点多。
...全文
2322 40 打赏 收藏 转发到动态 举报
写回复
用AI写文章
40 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
引用 38 楼 fyzqzpd 的回复:
说的再详细一点吧,如果不用remove函数,用find,一次查找一个元素,然后调用erase擦除,容器后边的元素整体移动一次,每移动一个元素就要调用元素的拷贝赋值操作符,然后再查找元素,再移动一次,但用remove函数的话只移动一次就搞定了。这就是remove的威力。list中有内置的remove,因为它不需要移动元素。
再等一天,看有没有反对的。
fuzigege 2013-06-22
  • 打赏
  • 举报
回复
我来猜测一下: 首先, STL的设计者可能是想所有容器都有移除特定数据的需求,因此整出来一个通用的std::remove算法,但是算法天生就不知道如何去修改容器的大小,因此在移除掉特定数据后,如果要调整容器大小,就必须借助容器自身的erase函数,因此就有了erase+remove的推荐写法了。 也许会有人说,为什么移除掉重复元素后,需要调整容器大小,不调整行不行。其实看一下remove的实现就知道了,remove完成以后末尾因为移除元素而空出来的位置其实他们的数据只是被复制到前面去了,但他们都保留了原先的数据,如果不将这些位置移除掉,后面继续用该容器,除非你每次都只访问begin到remove函数的返回值为止的位置,否则就会访问到重复数据。这也是Effective STL的作者推荐erase+remove写法的原因。 接下来的问题,为什么不给每个容器都写一份实现移除所有特定元素的实现。 其实有,list的erase就有一个重载版本可以移除特定数据的所有元素,但是vector就没有。其实原因我觉得还是在于性能,vector的作者可以认为erase+remove的做法对于vector来说已经够快了,自己再实现一份,也不见得会比erase+remove更快,因此不提供删除指定数据的erase版本。但是list作者就另外想了,因为list是链表,在链表上删除元素只用修改指针,不用复制数据,但是remove却是采用拷贝数据的方式来删除元素的,因此list作者就提供了一个比erase+remove更快的erase版本。 因此,现有的STL虽然有的地方用起来感觉很别扭,比如我们现在讨论到的erase+remove写法,但是我觉得肯定是STL设计者中权衡利弊,多方取舍下的版本,其性能也是有保证的。
  • 打赏
  • 举报
回复
引用 11 楼 zhao4zhong1 的回复:
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行! 单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 不要迷信书、考题、老师、回帖; 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实! 有人说一套做一套,你相信他说的还是相信他做的? 其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗? 不要写连自己也预测不了结果的代码!
话痨。
  • 打赏
  • 举报
回复
remove remove_if不会改变容器大小的。
赵4老师 2013-06-21
  • 打赏
  • 举报
回复
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行! 单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 不要迷信书、考题、老师、回帖; 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实! 有人说一套做一套,你相信他说的还是相信他做的? 其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗? 不要写连自己也预测不了结果的代码!
zhao1zhong6 2013-06-21
  • 打赏
  • 举报
回复
说的再详细一点吧,如果不用remove函数,用find,一次查找一个元素,然后调用erase擦除,容器后边的元素整体移动一次,每移动一个元素就要调用元素的拷贝赋值操作符,然后再查找元素,再移动一次,但用remove函数的话只移动一次就搞定了。这就是remove的威力。list中有内置的remove,因为它不需要移动元素。
zhao1zhong6 2013-06-21
  • 打赏
  • 举报
回复
这有什么奇怪的,for_each代替for循环大多数时候也只是让代码看起来简洁而已。
汗晕倒 2013-06-21
  • 打赏
  • 举报
回复
这个功能就够了,难道非要很多功能???
赵4老师 2013-06-21
  • 打赏
  • 举报
回复
public member function 
std::vector::erase<vector> iterator erase (iterator position);
iterator erase (iterator first, iterator last);
iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);
Erase elements
Removes from the vector either a single element (position) or a range of elements ([first,last)).

This effectively reduces the container size by the number of elements removed, calling their destructors.

Because vectors use an array as their underlying storage, erasing elements in positions other than the vector end causes the container to move all the elements after the segment erased to their new positions. This is generally an inefficient operation compared to the one performed for the same operation by other kinds of sequence containers (such as list or forward_list).


Parameters
position 
Iterator pointing to a single element to be removed from the vector.
Member types iterator and const_iterator are random access iterator types that point to elements. 
first, last 
Iterators specifying a range within the vector] to be removed: [first,last). i.e., the range includes all the elements between first and last, including the element pointed by first but not the one pointed by last.
Member types iterator and const_iterator are random access iterator types that point to elements. 


Return value
An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.

Member type iterator is a random access iterator type that points to elements.


Example
123456789101112131415161718192021222324 // erasing from vector
#include <iostream>
#include <vector>

int main ()
{
  std::vector<int> myvector;

  // set some values (from 1 to 10)
  for (int i=1; i<=10; i++) myvector.push_back(i);

  // erase the 6th element
  myvector.erase (myvector.begin()+5);

  // erase the first 3 elements:
  myvector.erase (myvector.begin(),myvector.begin()+3);

  std::cout << "myvector contains:";
  for (unsigned i=0; i<myvector.size(); ++i)
    std::cout << ' ' << myvector[i];
  std::cout << '\n';

  return 0;
} 


Output:

myvector contains: 4 5 7 8 9 10
 



Complexity
Linear on the number of elements erased (destructors) plus the number of elements after the last element deleted (moving).


Iterator validity
Iterators, pointers and references pointing to position (or first) and beyond are invalidated, with all iterators, pointers and references to elements before position (or first) guaranteed to keep referring to the same elements they were referring to before the call.


Data races
The container is modified.
None of the elements before position (or first) is accessed, and concurrently accessing or modifying them is safe.


See also
vector::pop_backDelete last element (public member function )vector::insertInsert elements (public member function )
rocktyt 2013-06-21
  • 打赏
  • 举报
回复
引用 30 楼 u010828523 的回复:
[quote=引用 28 楼 cqdjyy01234 的回复:] [quote=引用 27 楼 u010828523 的回复:] 难道真就这么个功能,有点吃惊啊。
就一行代码,正常的吧?[/quote] 决定置顶几天,有点不相信,看看有没有反驳的。两个函数组合起来就这么点功能,人家圣斗士星矢5人组合起来还能毁灭地球来。[/quote]这有什么好不相信的,真是奇葩
  • 打赏
  • 举报
回复
要有投票选择就好了,哎。
  • 打赏
  • 举报
回复
erase+remove就是为了删除多个重复的元素????
橡木疙瘩 2013-06-21
  • 打赏
  • 举报
回复
引用 23 楼 u010828523 的回复:
[quote=引用 20 楼 cqdjyy01234 的回复:] [quote=引用 18 楼 u010828523 的回复:] [quote=引用 15 楼 cqdjyy01234 的回复:] 你确定v.erase(9999);能通过编译?你用的什么编译器?你在8楼的回答不是显示编译错误吗?
是简写,请不要探讨豌豆有几种写法了,明白这个意思就可以。[/quote] 当然不是简写的问题,那请问你怎么实现?事实上,就是要erase和remove组合实现。当然你可以写其它代码达到这个效果,但是比这个更复杂。[/quote] 难道erase和remove组合实现,就是为了实现查找某数并删除的功能?并且能一下删除多个重复的该数?就这么点功能?没有其他???[/quote] 容器的erase和算法库的remove都是高内聚的函数,它们做的事情很单纯。 erase功能就是删除容器中的连续元素,而不关心这部分连续元素的取值 remove/remove_if功能就是去除序列中符合条件的元素,而不关心这些元素属于谁。 两个联合起来完成“从容器中删除符合条件的元素”这一功能。 事实上要实现这个功能还有一种写法:

  v.resize( remove(v.begin(), v.end(), 99999) - v.begin() );
这个方法与用erase+remove是一样的。因为remove已经把需要保留的元素移到了序列前面,需要删除的元素都在尾部,所谓“erase”其实就是“resize”。
  • 打赏
  • 举报
回复
引用 28 楼 cqdjyy01234 的回复:
[quote=引用 27 楼 u010828523 的回复:] 难道真就这么个功能,有点吃惊啊。
就一行代码,正常的吧?[/quote] 决定置顶几天,有点不相信,看看有没有反驳的。两个函数组合起来就这么点功能,人家圣斗士星矢5人组合起来还能毁灭地球来。
rocktyt 2013-06-21
  • 打赏
  • 举报
回复
引用 26 楼 cqdjyy01234 的回复:
[quote=引用 24 楼 rocktyt2 的回复:] [quote=引用 23 楼 u010828523 的回复:] [quote=引用 20 楼 cqdjyy01234 的回复:] [quote=引用 18 楼 u010828523 的回复:] [quote=引用 15 楼 cqdjyy01234 的回复:] 你确定v.erase(9999);能通过编译?你用的什么编译器?你在8楼的回答不是显示编译错误吗?
是简写,请不要探讨豌豆有几种写法了,明白这个意思就可以。[/quote] 当然不是简写的问题,那请问你怎么实现?事实上,就是要erase和remove组合实现。当然你可以写其它代码达到这个效果,但是比这个更复杂。[/quote] 难道erase和remove组合实现,就是为了实现查找某数并删除的功能?并且能一下删除多个重复的该数?就这么点功能?没有其他???[/quote]还真就这点功能 如果用remove_if,可以删除符合某条件的元素 顺便个人也认为这种写法是丑陋,难以理解的,但现在c++的stl就是这个样子 期待以后有更优美的写法吧 虽然我22楼那样说,我还是觉得应该把这种功能内置到容器里面去[/quote] vector从中间删除元素并不高效,所以这个功能不可能集成到容器中,这是STL的原则,避免低效的操作。如果真需要容器有这个功能,可以用其他容器,比如multiset。[/quote]的确 只能期待新的写法了
cqdjyy01234 2013-06-21
  • 打赏
  • 举报
回复
引用 27 楼 u010828523 的回复:
难道真就这么个功能,有点吃惊啊。
就一行代码,正常的吧?
  • 打赏
  • 举报
回复
难道真就这么个功能,有点吃惊啊。
cqdjyy01234 2013-06-21
  • 打赏
  • 举报
回复
引用 24 楼 rocktyt2 的回复:
[quote=引用 23 楼 u010828523 的回复:] [quote=引用 20 楼 cqdjyy01234 的回复:] [quote=引用 18 楼 u010828523 的回复:] [quote=引用 15 楼 cqdjyy01234 的回复:] 你确定v.erase(9999);能通过编译?你用的什么编译器?你在8楼的回答不是显示编译错误吗?
是简写,请不要探讨豌豆有几种写法了,明白这个意思就可以。[/quote] 当然不是简写的问题,那请问你怎么实现?事实上,就是要erase和remove组合实现。当然你可以写其它代码达到这个效果,但是比这个更复杂。[/quote] 难道erase和remove组合实现,就是为了实现查找某数并删除的功能?并且能一下删除多个重复的该数?就这么点功能?没有其他???[/quote]还真就这点功能 如果用remove_if,可以删除符合某条件的元素 顺便个人也认为这种写法是丑陋,难以理解的,但现在c++的stl就是这个样子 期待以后有更优美的写法吧 虽然我22楼那样说,我还是觉得应该把这种功能内置到容器里面去[/quote] vector从中间删除元素并不高效,所以这个功能不可能集成到容器中,这是STL的原则,避免低效的操作。如果真需要容器有这个功能,可以用其他容器,比如multiset。
cqdjyy01234 2013-06-21
  • 打赏
  • 举报
回复
个人认为这儿就是这个功能了。这比你写个循环,简单明了(前提是你熟悉STL),效率也差不多。
rocktyt 2013-06-21
  • 打赏
  • 举报
回复
引用 23 楼 u010828523 的回复:
[quote=引用 20 楼 cqdjyy01234 的回复:] [quote=引用 18 楼 u010828523 的回复:] [quote=引用 15 楼 cqdjyy01234 的回复:] 你确定v.erase(9999);能通过编译?你用的什么编译器?你在8楼的回答不是显示编译错误吗?
是简写,请不要探讨豌豆有几种写法了,明白这个意思就可以。[/quote] 当然不是简写的问题,那请问你怎么实现?事实上,就是要erase和remove组合实现。当然你可以写其它代码达到这个效果,但是比这个更复杂。[/quote] 难道erase和remove组合实现,就是为了实现查找某数并删除的功能?并且能一下删除多个重复的该数?就这么点功能?没有其他???[/quote]还真就这点功能 如果用remove_if,可以删除符合某条件的元素 顺便个人也认为这种写法是丑陋,难以理解的,但现在c++的stl就是这个样子 期待以后有更优美的写法吧 虽然我22楼那样说,我还是觉得应该把这种功能内置到容器里面去
加载更多回复(20)

64,683

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧