std::remove_if和erase无法从std::vector中删除元素

4

我正在练习LeetCode中的简单问题。我想使用lambda从向量中删除元素(第一次这样做,感觉很不错)。但是我得到了一个负指针new_end。

#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>   // std::greater

using namespace std;
int main()
{
    vector<int> a = { 2, 7, 11, 15 };
    int target = 9;

    auto new_end = std::remove_if(a.begin(), a.end(), [&a, target](const int x)
    {
        return std::count(a.begin(), a.end(), x) > target;  
    });
    a.erase(new_end, a.end());
    return 0;
}

没有出现错误,但new_end是一个负指针值。 图片描述

3
“negative pointer value”的意思是“负指针值”。您是否在某处打印了它,或者您是如何得出这个结论的? - 463035818_is_not_a_number
2
不存在负指针这种东西。 - Slava
2
new_end 是否等于 end?看起来应该是这样的。 - NathanOliver
1
iterator::end 没有指向有用的数据。它仅用于确定集合的结尾。 - Vinz
new_end的值看起来合理。我关心的一件事是在“remove_if”的谓词中使用了 count(a.begin(),a.end(),x)。一旦一个元素被“remove”,下一次调用谓词将通过超过new_end访问已删除的值。已删除的元素具有未指定的值。 - Sean Cline
显示剩余2条评论
2个回答

2
"std::remove_if(begin, end, pred)"返回一个迭代器,指向要删除的第一个元素或者如果没有与"pred"匹配的元素,则返回"end"。在您的情况下,后者是正确的。"
auto new_end = std::remove_if(a.begin(), a.end(),
    [&a, target](const int x) { return std::count(a.begin(), a.end(), x) > target; }
);

"new_end"等于"a.end()"。这个值在您的调试器中打印出来是垃圾值。但是,在你的情况下,它恰好工作了(可能是偶然)。
正如多位评论者指出的那样,一旦您的谓词返回一次“真”,范围[a.begin(), a.end)就会被修改,并且最后一个元素的值是未指定的1
这使得std::count(a.begin(), a.end(), x)返回未指定的值。
建议的解决方法是在remove_if开始移动东西之前先复制一个a。这可以通过按值捕获来完成:
auto new_end = std::remove_if(a.begin(), a.end(),
    [b=a, target](const int x) { return std::count(b.begin(), b.end(), x) > target; }
);

将副本初始化为新名称 b 只是强调它是一个副本。

1) 来自 std::remove_if

指向新逻辑结尾和物理结尾之间元素的迭代器仍然可解引用,但是元素本身具有未指定的值(根据 MoveAssignable 后置条件)。


2
我认为这段代码不起作用。std::remove_if 在 lambda 函数仍在计数并读取未指定元素的同时修改了范围。 - Quentin
1
如果谓词返回 true,则下一次调用谓词时,最后一个元素具有未指定的值。 - François Andrieux

-1

我想要从向量中删除大于9的数字,以下是代码

    vector<int> a = { 2, 7, 11, 15 };
    int target = 9;

    auto new_end = std::remove_if(a.begin(), a.end(), [](const int x)
    {
        return x > 9;

    });
    a.erase(new_end, a.end());
    return 0;

lambda函数的参数'x'将由remove_if提供,您不需要在捕获列表中添加任何内容


5
你是如何得出这个假设的?将变量“target”的值替换为硬编码的值并不是一个好主意。 - Slava
@Slava 这里没有任何假设,如果你知道 lambda 的工作原理,那么你就会明白它是如何工作的。你只需要创建一个单独的函数,然后将该函数传递进去即可。 - Daksh Gupta
4
“我假设希望删除大于9的数字”绝对是一个假设。 - François Andrieux
1
我的猜测是这就是OP想要的,但是不解释原始代码有什么问题就倾泻出一个解决方案并不是很有用。如果9在OP的实际用例中可能会变化,那么“你不需要在捕获列表中添加任何内容”并不一定正确,那个变量需要被捕获。 - Praetorian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接