繁体   English   中英

std :: remove_if - lambda,不从集合中删除任何东西

[英]std::remove_if - lambda, not removing anything from the collection

好吧,我希望我在这里犯了一个愚蠢的错误。 我有一个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返回的迭代器上调用erase,它应该是这样的:

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一起使用。 有关详细信息,请参阅此问题

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

在此输入图像描述

正如其他人所提到的,有一些方法可以使它发挥作用。 但是我的建议是完全避免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

如下面的评论所述,当删除多于1个元素时,此方法的成本比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)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM