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并坚持标准的基于迭代器的删除。 下面的习语既适用于listvector ,也不会产生意想不到的行为。

 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()来做清理。

在这里输入图像说明