【问题标题】:incorrect output using STL remove_if [duplicate]使用 STL remove_if 的输出不正确 [重复]
【发布时间】:2021-03-22 22:13:02
【问题描述】:

我正在尝试使用 std::remove_if 从整数向量中删除元素,但没有得到所需的输出。

初始向量成员:{0, 1, 2, 1, 3, 1, 4, 5, 1, 6, 1, 7, 1, 8, 1, 9}

所需输出:{0、2、3、4、5、6、7、8、9}

实际输出:{0, 2, 3, 4, 5, 6, 7, 8, 9, 6, 1, 7, 1, 8, 1, 9}

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <functional>

    class Equal
    {
    public:
    Equal(int a): a_(a){}
    bool operator()(int b)
    {
    return a_ == b;
    }
    
    private:
    int a_;
    };
    
    int main()
    {
    std::vector<int> vi{0, 1, 2, 1, 3, 1, 4, 5, 1, 6, 1, 7, 1, 8, 1, 9};
    
    std::cout << std::endl;
    std::remove_if(vi.begin(), vi.end(), Equal(1));
    for (const auto &i : vi) std::cout << i << " ";
    return 0;
    }

【问题讨论】:

    标签: c++ c++11


    【解决方案1】:

    vector 在调用之前和之后的元素数量一样多 std::remove_if:

    删除是通过移动(通过move 赋值)范围内的元素来完成的,这样不被删除的元素出现在范围的开头。

    ... 和 std::remove_if 将迭代器返回到“已删除”元素的开头,您可以使用该迭代器实际 erase 元素:参见 Erase–remove idiom

    vi.erase(
        std::remove_if(vi.begin(), vi.end(), Equal(1)), // returns iterator
        vi.end()                                        // erase to the end
    );
    

    Demo

    另请注意,std::vector 在 C++20 中获得了一个新的专用函数,它可以同时做这两件事,即 std::erase_if

    例子:

    std::erase_if(vi, Equal(1));
    

    【讨论】:

    • 只是进一步解释一下:标准迭代器不支持从容器中擦除元素,因此std::remove_if 无法根据需要擦除元素。所以我们必须在之后这样做,如this answer所示。事实证明,这是一种非常有效的擦除元素的方法,尤其是对于线性内存,如使用向量。
    • 可能有助于提一下,即使在调用 std::remove_if 之后元素的数量相同,它们也可能不是相同的元素。在返回的迭代器之后,本质上是“垃圾”。例如,在问题中我们可以看到 9 两次。
    • 非常感谢泰德。
    • @ss-haze 不客气!
    猜你喜欢
    • 2021-11-23
    • 1970-01-01
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    • 2013-07-27
    • 1970-01-01
    • 2018-10-31
    • 1970-01-01
    相关资源
    最近更新 更多