我在考虑这个循环:
struct tmp {
int min;
int max;
tmp(int a, int b) :min(a), max(b){};
};
std::vector <tmp> data;
for (auto tmp_a : data){
if(tmp_a.min == 0){
//how to delete tmp_a item from data from there?
}
}
当然我可以迭代这个循环,但我不认为这是最快的方法。 (当然我可能是错的 - 然后纠正我)
问题: 如何删除范围循环内的项目?(使用最快的方法)
答案 0 :(得分:8)
放弃循环并使用擦除 - 删除习惯用法。
data.erase(std::remove_if(data.begin(), data.end(), [] (tmp t) {
return t.min == 0;
}), data.end());
答案 1 :(得分:1)
template<class C, class F>
void remove_erase_if( C& c, F&& f ) {
using std::begin; using std::end;
c.erase( std::remove_if( begin(c), end(c), std::forward<F>(f) ), end(c) );
}
这是一个采用容器c
和测试函数f
的算法。它会删除通过测试的所有元素f
。
我发现将它捆绑在一起就像这样可以减少忘记,end(c)
组件的机会,并且两个操作(删除然后删除)经常捆绑在一起,使得一个操作清理调用代码。
我们接受您的代码:
for (auto tmp_a : data){
if(tmp_a.min == 0){
//how to delete tmp_a item from data from there?
}
}
并替换控制循环:
remove_erase_if( data, [&](tmp const& tmp_a){
return (tmp_a.min == 0);
});
或在C ++ 14中:
remove_erase_if( data, [&](auto&& tmp_a){
return (tmp_a.min == 0);
});
如果我们从lambda返回true
,则元素将从容器中删除,如果我们返回false
,则会保留该元素。
虽然将tmp&
编译,但修改tmp_a
在技术上是未定义的行为。我认为这是标准的过度规范。但是如果你需要迭代和修改,你需要编写自己的remove_if
版本:最简单的实现没有修改元素和/或删除它们的问题。
template<class It, class F>
It my_remove_if( It start, It end, F f ) {
It target = start;
for(It& it = start; it != end; ++it) {
if (f(*it))
continue;
if (it != target)
*target = std::move(*it);
++target;
}
return target;
}
匹配std::remove_if
接口(我更喜欢使用F&&
,但兼容性很重要),做同样的事情,除了明确允许在删除元素时修改容器的内容。
答案 2 :(得分:-1)
另一种可能性是使用以下内容:
auto iter = data.begin();
while( iter != data.end() ) {
if( iter->min == 0 )
iter = data.erase(iter);
else
++iter;
}
适用于所有容器(包括自c ++ 11以来的关联),这也是erase
返回迭代器的原因。如果在clearly express intent
中与擦除相比更好或更差 - 删除 - 成语是一个争论话题,我个人更喜欢它。
请注意,对于连续容器,例如vector
,每个erase
都会移动后面的所有项目,这可能效率很低,尤其是当目标硬件没有预先设置时提取或值类型不支持移动语义。