49

好吧,我想我在这里犯了一个愚蠢的错误。我有一个 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; 
                            });
4

4 回答 4

85

您需要在从 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());
于 2010-12-18T15:27:27.953 回答
22

remove_if不会从列表中删除任何内容,只会将它们移动到末尾。您需要将它与erase. 有关更多详细信息,请参阅此问题

于 2010-12-18T15:26:24.803 回答
13

remove_if不执行调整大小,而是将迭代器返回到未删除的最后一个元素之后的元素。可以传递这个迭代器来进行erase()清理。

在此处输入图像描述

于 2016-11-10T08:00:25.543 回答
1

正如其他人所提到的,有办法让它发挥作用。但是,我的建议是完全避免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比删除超过 1 个元素的成本更高。

remove_if通过从向量中更前面的元素复制元素,并用紧靠其前面的那个覆盖应该从向量中删除的向量来工作。例如: remove_if 在向量上调用以删除所有 0 元素:

0 1 1 0 1 0

结果是:

1 1 1 0 1 0

请注意向量是如何不正确的。那是因为remove_if返回最后一个有效元素的迭代器......它不会自动调整向量的大小。您仍然需要调用v.erase()从调用返回的迭代器remove_if

下面是一个例子

#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)
}
于 2013-05-04T01:22:26.023 回答