从向量中删除最后一个元素会导致迭代出现问题

Huz*_*hid 2 c++ iterator stdvector

这是我的代码:

vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
v.push_back(7);

for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
    if (*it == 7)
        v.erase(it);
    cout << *it << endl;
}
Run Code Online (Sandbox Code Playgroud)

问题是,for循环不会停止运行并打印垃圾值。您能否对这个问题给出一些见解...比如最后一个元素可能存储有关大小或地址的信息end()

使用该erase()方法对于向量中的其他位置(最后一个元素除外)效果很好。

控制台日志显示垃圾值,如下所示:

34603778
35652354
50397954
34603592
34603536
34603536
34603536
34603536
34603794
36700688
34603536
34603536
34865684
51511824
34603536
34865680
Run Code Online (Sandbox Code Playgroud)

pad*_*ddy 7

无论您从向量中的哪个位置删除,您的程序都有未定义的行为。正如文档所说,该函数:

在擦除点或擦除点之后使迭代器和引用无效,包括 end() 迭代器。

所以,你的迭代器在你擦除的那一刻就死了。这就是为什么该函数返回一个新的迭代器(到现在位于您刚刚删除的位置的项目)。您必须更新循环的迭代器才能使用它。

从循环中的标准容器中擦除的惯用方法是在循环体本身中步进迭代器:

for (vector<int>::iterator it = v.begin(); it != v.end(); )
{
    if (*it == 7) {
        it = v.erase(it);
    } else {
        cout << *it << endl;
        ++it;
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,这通常不是从向量中删除项目的好方法。如果向量包含大量要删除的值怎么办?您的操作变得非常低效,因为每次擦除都必须对向量中的剩余项目进行混洗。

所以更好的方法是擦除-删除习惯用法

v.erase(std::remove(v.begin(), v.end(), 7), v.end());
Run Code Online (Sandbox Code Playgroud)

从 C++20 开始,这进一步简化

std::erase(v, 7);
Run Code Online (Sandbox Code Playgroud)