【问题标题】:Why do we need to decrement iterator while deleting from vector?为什么我们在从向量中删除时需要递减迭代器?
【发布时间】:2021-03-17 17:45:55
【问题描述】:

我有一个下面的程序。我需要了解为什么我们在使用擦除方法时需要递减指针? 还有没有更好的方法不会造成这种混乱?

#include <iostream>
#include <vector>
using namespace std;
 

int main()
{
    vector<int> myvector{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
 
    for (auto i = myvector.begin(); i != myvector.end(); ++i) {
        if (*i % 2 == 0) {
            myvector.erase(i);
            i--;// why do we need to decrement ?
        }
    }
 
    // Printing the vector
    for (auto it = myvector.begin(); it != myvector.end(); ++it)
        cout << ' ' << *it;
    return 0;
}

【问题讨论】:

    标签: c++ erase


    【解决方案1】:

    我需要了解为什么我们在使用擦除方法时需要递减指针?

    你没有,也不应该。正确的做法是使用erase 的返回值。目前您的程序具有未定义的行为,因为您正在修改无效的迭代器。

    for (auto i = myvector.begin(); i != myvector.end();) {
        if (*i % 2 == 0) {
            i = myvector.erase(i);
        } else {
            ++i;
        }
    }
    

    还有没有更好的方法不会造成这种混乱?

    是的,std::remove_if

    auto is_even = [](int i){ return (i % 2) == 0; };
    auto last = std::remove_if(myvector.begin(), myvector.end(), is_even);
    myvector.erase(last, myvector.end());
    

    【讨论】:

    • 在这个 { i = myvector.erase(i);} 中,现在 i 到底指向哪里,下一个有效还是之前的一个?
    • @FrançoisAndrieux 我的意思是,对于例如 auto myiterator = myvector.erase(i),这个“myiterator”现在指向哪里?
    • @unixlover 它指的是曾经在被删除的元素之后的元素。换句话说,对于std::vector,它指的是现在位于被移除元素曾经占据的索引处的对象。
    • @FrançoisAndrieux 谢谢好友 :)
    【解决方案2】:

    Caleth 给了你一个很好的答案,但我要补充一些信息:

    for (auto i = myvector.begin(); i != myvector.end(); ++i) {
        if (*i % 2 == 0) {
            myvector.erase(i);
            i--;// why do we need to decrement ?
        }
    }
    

    这是你的代码。对于我的解释,让我们相信迭代器只是一个索引(一个 int)。不是,但它有助于理解。

    假设 myvector 包含整数 0..10,然后删除 4。一旦这样做:

    0 1 2 3 5 6 7 8 9 10
    

    现在,想象一下你的循环。您到达 for 循环的底部并递增 i - 它现在有 5,但是您跳过检查旧的 myvector[5] - 现在存储在 myvector[4] 中 - 是否适合您的 if 语句.

    另一种写法:

    for (auto i = myvector.begin(); i != myvector.end(); ) { 如果 (...) ... 别的 { ++i; } }

    也就是说,如果你不删除,你只会增加迭代器。这样可以避免在您删除的项目之后跳过该项目(因为它移动到了被删除的人的位置)。

    但是,这是错误的做法,并且 Caleth 对如何正确执行此操作有更好的答案。

    【讨论】:

      猜你喜欢
      • 2010-11-16
      • 2016-08-01
      • 1970-01-01
      • 2012-08-02
      • 2017-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-18
      相关资源
      最近更新 更多