Вопрос

Хорошо, я ожидаю, что я сделал тупой ошибку здесь. У меня есть список DisplayDevice3D, и каждый DisplayDevice3D содержит список DisplayMode3D. Я хочу удалить все элементы из списка DisplayDevice3D, у которых нет никаких DisplayMode3D. Я пытаюсь использовать лямбду, чтобы сделать это, т.е.:

    // If the device doesn't have any modes, remove it.

  std::remove_if(MyDisplayDevices.begin(), MyDisplayDevices.end(),
   [](DisplayDevice3d& device) 
   { 
    return device.Modes.size() == 0; 
   }
  ); 

Несмотря на то, что из 6 DisplayMode3D в MyDisPlayDevices, только 1 имеет какие -либо 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. Анкет Посмотри это вопрос Больше подробностей.

remove_if Не выполняет изменение размера, но вместо этого он просто возвращает итератор в элемент, который следует за последним элементом, не удаленным. Этот итератор может быть передан в erase() сделать уборку.

enter image description here

Как упоминали другие, есть способы заставить его работать. Однако мой совет - полностью избежать 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)
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top