[英]Removing elements from vector using remove_if
I am trying to remove vector elements using remove_if
. 我试图使用
remove_if
删除矢量元素。 But unsuccessfully. 但没有成功。 What am I doing wrong?
我究竟做错了什么?
Here's my code: 这是我的代码:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
void printme(std::vector<int>& a){
for(const auto& item: a)
std::cout << item << std::endl;
}
int main()
{
std::vector<int> a {1, 2, 3, 4, 5, 6};
printme(a);
a.erase( (std::remove_if(a.begin(), a.end(), [](const int& x){
return x == 2;
}), a.end()));
printme(a);
}
My output is just: 我的输出只是:
1 2 3 4 5 6
1 2 3 4 5 6
Expected output: 预期产量:
1 2 3 4 5 6 1 3 4 5 6
1 2 3 4 5 6 1 3 4 5 6
You are using an overload of the std::vector::erase()
member function that takes a single iterator as parameter. 您正在使用
std::vector::erase()
成员函数的重载,该函数将单个迭代器作为参数。 As the argument to erase()
you are providing the iterator a.end()
, since the following expression: 作为
erase()
的参数,你提供了迭代器a.end()
,因为下面的表达式:
(std::remove_if(a.begin(), a.end(), [](const int& x){ return x == 2; }), a.end()))
evaluates to a.end()
(ie, because of the comma operator). 计算到
a.end()
(即,因为逗号运算符)。
The iterator passed to the overload of erase()
that takes a single iterator must be dereferenceable . 传递给
erase()
的重载的迭代器必须是可解除引用的单个迭代器。 However, the iterator a.end()
is not dereferenceable, therefore, the call to erase()
results in undefined behavior . 但是,迭代器
a.end()
不能解除引用,因此,对erase()
的调用会导致未定义的行为 。
To use the overload that takes two iterators, remove the parenthesis surrounding the call to std::remove_if
: 要使用带有两个迭代器的重载,请删除对
std::remove_if
的调用周围的括号:
a.erase(std::remove_if(a.begin(), a.end(), [](const int& x){
return x == 2;
}), a.end());
You're adding superfluous parentheses, change it to 您正在添加多余的括号,将其更改为
a.erase( std::remove_if(a.begin(), a.end(), [](const int& x){
return x == 2;
}), a.end());
Note that the comma operator just returns the last operand, that means you're passing a.end()
to erase
, which leads to UB. 请注意, 逗号运算符只返回最后一个操作数,这意味着您将
a.end()
传递给erase
,这将导致UB。
The other answers have pointed out what the problem was. 其他答案指出了问题所在。 I want to say, it will be easier to notice these kinds of problems by simplifying your code.
我想说,通过简化代码可以更容易地注意到这些问题。
I suggest using: 我建议使用:
int main()
{
std::vector<int> a {1, 2, 3, 4, 5, 6};
printme(a);
auto it = std::remove_if(a.begin(), a.end(), [](const int& x){ return x == 2; });
a.erase(it, a.end());
printme(a);
}
You just had too many parentheses in the function call. 你在函数调用中只有太多的括号。
a.erase(std::remove_if(a.begin(), a.end(), [](const int& x) {return x == 2;}), a.end());
Just remove one parentheses before the std::remove_if
and at the end of the call. 只需在
std::remove_if
之前和调用结束时删除一个括号。
Your problem is that you are doing the erase-remove idiom inline. 你的问题是你正在内联擦除删除习语。 It is very error prone.
这很容易出错。
template<class C, class F>
void erase_remove_if( C&& c, F&& f ) {
using std::begin; using std::end;
auto it = std::remove_if( begin(c), end(c), std::forward<F>(f) );
c.erase( it, end(c) );
}
this little helper function does the error prone part of erase remove in isolation from other noise. 这个小帮手功能可以将易出错的部分擦除与其他噪声隔离开来。
Then: 然后:
a.erase( (std::remove_if(a.begin(), a.end(), [](const int& x){
return x == 2;
}), a.end()));
becomes 变
erase_remove_if(
a,
[](const int& x){
return x == 2;
}
);
and suddenly your code works. 突然你的代码工作了。
Now the proximate cause was you had a typo: 现在最直接的原因是你有一个错字:
a.erase(
(
std::remove_if(
a.begin(),
a.end(),
[](const int& x){
return x == 2;
}
),
a.end()
)
);
here I have expanded the line's structure. 在这里我扩展了线的结构。 You can see from the above that you only passed one argument to
erase
; 你可以从上面看到你只传递了一个参数来
erase
; namely a.end()
, because you passed it ( some remove expression, a.end() )
in brackets. 即
a.end()
,因为你在括号中传递了它( some remove expression, a.end() )
。 This invoked the comma operator: so it ran the remove expression (moving the element 2
to the end), then discarded the returned iterator and evaluated to a.end()
. 这调用了逗号运算符:所以它运行了remove表达式(将元素
2
移动到结尾),然后丢弃返回的迭代器并计算到a.end()
。
We then passed a.end()
to erase
, which is not a valid iterator to pass to erase
. 然后我们将
a.end()
传递给erase
,这不是传递给erase
的有效迭代器。 So your program is ill-formed, and UB results. 所以你的程序是不正确的,UB结果。
That is only the proximate cause. 这只是近因 。 There are many mistakes you can easily make when manually doing erase-remove;
手动擦除时,您可以轻松犯下许多错误; the code is fragile and full of repetition.
代码很脆弱,充满了重复。
DRY is the principle that you want a single point of customization, and you don't want to repeat things that don't need repeating. DRY是您希望单点自定义的原则,并且您不想重复不需要重复的事情。
erase_remove_if
is my attempt to apply DRY to avoid exactly this kind of error. erase_remove_if
是我尝试应用DRY以避免这种错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.