std :: list removal(C ++)

时间:2016-06-11 21:13:26

标签: c++ c++11

我使用std :: list遇到了一些奇怪的行为。问题是,当我删除列表中的当前元素时,它会使该元素无效。当我使用for( auto& iter : list)循环遍历元素时,它会卡在应该删除的元素上。我有一个最小的可编辑示例来说明这一点:

    #include <iostream>
    #include <list>
    #include <memory>
    int main() {
        std::list<unsigned int> wholeNumbers;
        while( wholeNumbers.size() < 20 ) {
            wholeNumbers.push_back( wholeNumbers.size() );
        }
        for( auto wholeNumber : wholeNumbers ) {
            std::cout << "Deleting entries. Value is: " << wholeNumber << std::endl;
            std::cout << "Old size: " << wholeNumbers.size() << std::endl;
            wholeNumbers.remove( wholeNumber );
            std::cout << "New size: " << wholeNumbers.size() << std::endl;
        }
    }

期望的结果是吐出递增值和递减的大小。但是,我遇到的结果如下:

Deleting entries. Value is: 0
Old size: 20
New size: 19
Deleting entries. Value is: 0
Old size: 19
New size: 19
Deleting entries. Value is: 0
Old size: 19
New size: 19
Deleting entries. Value is: 1901208
Old size: 19
New size: 19
Deleting entries. Value is: 0
Old size: 19
New size: 19
Deleting entries. Value is: 0
Old size: 19
New size: 19
Deleting entries. Value is: 0
Old size: 19
New size: 19
Deleting entries. Value is: 1901208
Old size: 19
New size: 19

然后无限期地重复。

我的编译器信息是:gcc version 5.3.0 (x86_64-posix-sjlj-rev0, Built by MinGW-W64 project)

如果我错误地认为这应该按照我的意愿行事,我很好奇。

致以最诚挚的问候,

3 个答案:

答案 0 :(得分:2)

来自{{3}}:

  

擦除元素的引用和迭代器无效。

基于for循环的范围使用隐式迭代器。 remove正在删除迭代器指向的元素,因此它变为无效,并且您有未定义的行为,它可能会擦除您的硬盘驱动器。

相反,获取一个显式迭代器。调用erase,而不是remove,并将迭代器设置为erase的返回值以继续迭代(返回值:&#34;迭代器跟随最后删除的元素。&#34; )

答案 1 :(得分:1)

list::remove

  

迭代器有效性:引用函数删除的元素的迭代器,指针和引用无效。

基于for循环的范围在内部使用迭代器,所以你做的是使迭代器无效,因此你期望的行为不是你所期望的。

std::remove不同,http://en.cppreference.com/w/cpp/container/list/erase只是将元素移动到容器的末尾并返回指向第一个元素的指针&#34;删除&#34; - 因此需要着名的erase-remove-idiom-list :: remove实际上调用了析构函数。

答案 2 :(得分:0)

在第一次迭代中,您成功删除了第一个元素,以及第一个元素和std :: list的第二个元素之间的连接。所以它在第二次迭代中遇到了问题,因为for循环无法将指向具有未定义值的已删除元素的auto wholeNumber设置为std :: list的第二个元素。