逐步删除列表元素

Erasing list elements step by step

我想一个一个地删除列表元素。在删除任何列表元素之前,我想查看整个列表。

#include <iostream>
#include <list>
int main()
{
    std::list<int>numbers{0,1,2,3,4,5,6,7,8,9};
    auto it=numbers.begin();
    for(int i=0;i<10;i++){
        for(auto j:numbers)
        std::cout<<j<<" ";
        std::cout<<std::endl;
        it=numbers.erase(it);
        it++;
    }
    return 0;
}

输出:

0 1 2 3 4 5 6 7 8 9 
1 2 3 4 5 6 7 8 9 
1 3 4 5 6 7 8 9 
1 3 5 6 7 8 9 
1 3 5 7 8 9 
1 3 5 7 9 
double free or corruption (out)

为什么这个过程只处理了一半的元素。如何逐步删除所有列表元素?我知道我可以使用 numbers.clear(),但我不需要那个。

另外,为什么擦除不按顺序进行? (先删0,再删2,再删4)?

    it=numbers.erase(it);
    it++;

在第一行中,列表删除了迭代器指向的元素和 returns 指向下一个元素的迭代器。旧元素不再存在,传递给 erase()it 变得无效。这就是为什么你必须使用返回的迭代器,它指向下一个元素。

然后第二行跳过该行,迭代器不再指向新列表的开头。

您正在从列表中每隔一个元素删除一次:擦除、跳过、擦除、跳过、擦除、跳过……

#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>

template <typename Container>
void print(const Container& container, std::ostream& sout = std::cout) {
  std::copy(std::begin(container), std::end(container),
            std::ostream_iterator<typename Container::value_type>(sout, " "));
  sout << '\n';
}

int main() {
  std::list<int> numbers{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

  // Note that the update action is skipped
  for (auto it = numbers.begin(); it != numbers.end();) {
    print(numbers);
    it = numbers.erase(it);
  }

  return 0;
}

这只能用迭代器来完成。我将打印移到了它自己的功能中。这里的关键是循环声明不再负责更新迭​​代器,因为它现在发生在循环体中。阅读 std::list<T>::erase() 告诉我们函数 returns 是一个迭代器,它指向被擦除后的元素。由于我们从头开始擦除,所以擦除动作自然会遍历整个列表。

同样重要的是要注意循环必须以这种方式完成。从列表中删除会使列表的所有 pre-existing 迭代器失效。现在唯一有效的是 erase() 函数返回的迭代器。

问题出在这两行

it=numbers.erase(it);
it++;

函数,list::erase,returns一个指向最后一个被擦除元素之后的元素的迭代器。在这里,您的代码从列表中删除项目并将 it 设置为列表中的下一个元素。然后指令 it++ 将迭代器再前进一位,因此跳过列表中的一项。

简单的解决方案是注释掉 it++ 行:

#include <iostream>
#include <list>
int main()
{
    std::list<int>numbers{0,1,2,3,4,5,6,7,8,9};
    auto it=numbers.begin();
    for(int i=0;i<10;i++)
    {
        for(auto j:numbers)
            std::cout<<j<<" ";
        std::cout<<std::endl;
        it=numbers.erase(it);
        //it++;
    }
    return 0;
}

这给出了这个输出:

0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9
3 4 5 6 7 8 9
4 5 6 7 8 9
5 6 7 8 9
6 7 8 9
7 8 9
8 9
9