std :: remove_if – lambda,不会从集合中删除任何东西
好的,我希望我在这里犯了一个愚蠢的错误。 我有一个DisplayDevice3d列表,每个DisplayDevice3d包含一个DisplayMode3d列表。 我想从DisplayDevice3d列表中删除没有任何DisplayMode3d的所有项目。 我正在尝试使用Lambda来做到这一点,即:
// If the device doesn't have any modes, remove it. std::remove_if(MyDisplayDevices.begin(), MyDisplayDevices.end(), [](DisplayDevice3d& device) { return device.Modes.size() == 0; } );
即使在MyDisplayDevices中的6个DisplayMode3d中,只有1个在其Modes集合中具有任何DisplayMode3d,但是没有任何内容从列表中移除。
我在这里犯了什么错误?
编辑:
嗯,我的错误是我应该使用MyDisplayDevices.remove_if而不是std :: remove_if,但是下面的答案是正确的使用std :: remove_if:p。
MyDisplayDevices.remove_if( [](DisplayDevice3d const & device) { return device.Modes.size() == 0; });
您需要从remove_if返回的迭代器上调用擦除,它应该看起来像这样:
auto new_end = std::remove_if(MyDisplayDevices.begin(), MyDisplayDevices.end(), [](const DisplayDevice3d& device) { return device.Modes.size() == 0; }); MyDisplayDevices.erase(new_end, MyDisplayDevices.end());
remove_if
不会从列表中删除任何东西,只是将它们移动到结束。 你需要使用它和erase
。 看到这个问题的更多细节。
正如其他人所说,有办法使其工作。 不过,我的build议是完全避免remove_if
并坚持标准的基于迭代器的删除。 下面的习语既适用于list
和vector
,也不会产生意想不到的行为。
for( vector<TYPE>::iterator iter = vec.begin() ; iter != vec.end() ; ) if( iter->shouldRemove ) iter = vec.erase( iter ) ; // advances iter else ++iter ; // don't remove
如下面的评论所提到的,当多于一个的元素被移除时,这个方法的成本比remove_if
要高。
remove_if
通过复制向量中更前面的元素,并覆盖应该从前面的向量中删除的向量。 例如:remove_if在一个向量上调用来删除全部0个元素:
0 1 1 0 1 0
结果是:
1 1 1 0 1 0
注意向量如何不正确。 这是因为remove_if
将迭代器返回到最后一个有效元素…它不会自动调整向量的大小。 您仍然需要调用从remove_if
调用返回的迭代器上的v.erase()
。
下面是一个例子
#include <stdio.h> #include <vector> #include <algorithm> #include <functional> using namespace std; void print( vector<int> &v ) { for( int i : v ) printf( "%d ", i ); puts(""); } int main() { vector<int> v = { 0, 1, 1, 0, 1, 0 }; print( v ); // 0 1 1 0 1 0 vector<int>::iterator it = remove_if( v.begin(), v.end(), [](int i){ return i == 0; } ); print( v ); // 1 1 1 0 1 0 v.erase( it, v.end() ); // actually cut out values not wanted in vector print( v ); // 1 1 1 (correct) }
remove_if
不会执行大小调整,而只是将迭代器返回到最后一个元素未被移除的元素。 这个迭代器可以传递给erase()
来做清理。