火龙信奥
  • 首页
  • 课程
  • 题库
  • 打卡
    • 代码对战
    • 快速对战
  • 题单
  • 团队
  • 荣誉墙
  • 商城
  • 登录 / 注册

vector.erase()函数的常见陷阱

作者: 作者的头像   huolong , 时间:2022-10-22 11:00:29 , 所有人可见, 阅读  15

使用方式:

vector::erase():从指定容器删除指定位置的元素或某段范围内的元素

vector::erase()方法有两种重载形式

如下:

iterator erase(iterator _Where);

iterator erase(iterator _First, iterator _Last);

如果是删除指定位置的元素时:

返回值是一个迭代器,指向删除元素下一个元素;

如果是删除某范围内的元素时:返回值也表示一个迭代器,指向最后一个删除元素的下一个元素;

举例,在循环中用erase删除某个值

对 vector 尾部进行插入和删除操作可以很方便地通过 vector.push_back() 和 vector.pop_back() 函数来进行。

但是想要对中间部分的数据进行增删操作,就需要使用到迭代器。

为了对迭代器的使用进行学习,我们先定义一个整形数组v,并且给他赋初值:

for(int i=10; i<=1000; i+=10) v.push_back(i) ;

接下来,我们给数组插入5个1000,并且尝试使用迭代器将5个1000全部删除:

v.insert(v.begin(), 5, 1000);

陷阱1:生成野指针,导致程序崩溃

写的时候如果不加思索的话,很可能会写出以下的代码:

for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        if (*it == 1000)
        {
            v.erase(it); 
        }
    }

乍一看,当 it 指针找到值为1000的元素时,将 it 指向的元素从 v 中删除,似乎没有问题,那么我们运行一下看看结果:程序崩溃。

很不幸,程序崩溃了。略加思索后发现原因如下:当执行第一个v.erase(it)时,指针被删除,且没有给其重新定向,it就变成了一个野指针,当循环再次调用时,就会引发程序崩溃!

陷阱2:删除不完全

既然陷阱1导致 it 变成了野指针,那么有什么方法可以避免呢?其实很简单,只要给 it 重新定向就可以:

for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        if (*it == 1000)
        {
            it = v.erase(it); 
        }
    }

这次it不会变成野指针了,程序是可以正常运行了,那么运行结果呢? 我们预期的结果是将5个1000全部删除,但是结果中竟然还剩下了两个1000,那就只能从程序逻辑再次进行分析:

在一次循环内部,当执行了 v.erase() 后, it 指针会自动指向被删除了的元素的下一个位置,这个时候再执行循环体中的 it++,就会导致 it 直接指向了下下个元素! 当第一个1000被删除后, it 指向了第三个1000,并且将其删除,然后又指向了第5个1000,将其删除。因此结果中,第二个和第四个1000就被保留了,没有删除干净。

其实,这种写法的后果不仅仅是删除不干净那么简单:如果在数组最后的位置还有一个1000呢?当最后一个1000被删除后, it 直接指向了数组的最后一位数字的后一位,超出了数组的界限,就会引发程序崩溃!

正确使用:

既然原因找到了,那么就针对性地对程序进行修改:如果我们不在 for 循环条件中让 it 指向下一位,而是在函数体中,做一个条件判定呢?

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

分析一下上面的程序:在一次循环中,如果执行了 v.erase() 函数,那么 it 会自动指向下一个位置,在for()循环条件中并未传达 it++ 的指令,因此 it 能够正常地指向下一个元素而不是下下个元素;如果没有执行 v.erase() 函数,那么就手动让 it 指向下一个元素。

再次运行程序,结果正确:

vector<int> v ;
int main(){
    for(int i=10; i<=1000; i+=10) v.push_back(i) ;
    v.insert(v.begin(), 5, 1000);
    for (vector<int>::iterator it = v.begin(); it != v.end(); )
    {
        if (*it == 1000)
        {
            it = v.erase(it);
        }
        else
        {
            it++;
        }
    }
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++){
        cout << *it <<endl;
    }
    return 0;
}


—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com

©2026加盟我们 | 关于我们 | ACM课程 | 常见问题 | 成果墙 | 评测记录 | 浙ICP备2021013995号
在线画图 | OI WIki | 打字练习
火龙信奥
请输入登录信息


请完成安全验证
验证码底图 滑块
向右拖动滑块完成验证
请输入用户名 / 绑定的手机号码



请输入注册信息(手机号验证码注册)





验证码5分钟有效,60秒内不可重复获取,每日最多3次

微信登录

微信登录二维码

正在生成二维码...

账号已过期,请续期。
去续期

绑定手机号

📱

为了更好地保护您的账号安全,享受完整的平台服务

请您尽快绑定手机号码