我正在尝试使用remove_if
删除矢量元素。但是没有成功。我究竟做错了什么?
这是我的代码:
#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);
}
我的输出是:
1 2 3 4 5 6
预期输出:
1 2 3 4 5 6 1 3 4 5 6
答案 0 :(得分:19)
您正在使用std::vector::erase()
成员函数的重载,该重载将单个迭代器作为参数。作为erase()
的参数,您要提供迭代器a.end()
,因为以下表达式:
(std::remove_if(a.begin(), a.end(), [](const int& x){ return x == 2; }), a.end()))
评估为a.end()
(即,由于逗号运算符)。
传递给具有单个迭代器的erase()
重载的迭代器必须是 dereferenceable 。但是,迭代器a.end()
不可取消引用,因此,对erase()
的调用会导致未定义的行为。
要使用需要两个迭代器的重载,请删除对std::remove_if
的调用周围的括号:
a.erase(std::remove_if(a.begin(), a.end(), [](const int& x){
return x == 2;
}), a.end());
答案 1 :(得分:8)
您要添加多余的括号,将其更改为
a.erase( std::remove_if(a.begin(), a.end(), [](const int& x){
return x == 2;
}), a.end());
请注意,comma operator仅返回最后一个操作数,这意味着您正在将a.end()
传递给erase
,这将导致UB。
答案 2 :(得分:7)
其他答案指出了问题所在。我想说的是,通过简化代码,可以更容易注意到这些类型的问题。
我建议使用:
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);
}
答案 3 :(得分:5)
函数调用中括号过多。
a.erase(std::remove_if(a.begin(), a.end(), [](const int& x) {return x == 2;}), a.end());
只需在std::remove_if
之前和通话结束时删除一个括号即可。
答案 4 :(得分:3)
您的问题是您正在内联执行“擦除-删除”习惯用法。这很容易出错。
char[]
这个小辅助功能可以将擦除的容易出错的部分与其他噪音隔离开来。
然后:
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) );
}
成为
a.erase( (std::remove_if(a.begin(), a.end(), [](const int& x){
return x == 2;
}), a.end()));
您的代码突然起作用。
现在最直接的原因是您有错字:
erase_remove_if(
a,
[](const int& x){
return x == 2;
}
);
在这里,我扩展了生产线的结构。从上面可以看到,您仅将一个参数传递给a.erase(
(
std::remove_if(
a.begin(),
a.end(),
[](const int& x){
return x == 2;
}
),
a.end()
)
);
;即erase
,因为您在括号中传递了a.end()
。这会调用逗号运算符:因此它运行remove表达式(将元素( some remove expression, a.end() )
移动到末尾),然后丢弃返回的迭代器并求值为2
。
然后,我们将a.end()
传递给a.end()
,这不是传递给erase
的有效迭代器。因此,您的程序格式不正确,并且会产生UB结果。
这只是最接近的原因。手动执行删除删除操作时,很容易犯很多错误。该代码易碎,并且重复很多。
DRY是原则,您需要单点自定义,并且您不想重复不需要重复的事情。 erase
是我尝试应用DRY以避免这种错误的方法。