Pregunta

Ok, espero que he cometido un error tonto aquí. Tengo una lista de DisplayDevice3d y cada DisplayDevice3d contiene una lista de DisplayMode3d. Quiero eliminar todos los elementos de la lista de DisplayDevice3d que no tienen ninguna de DisplayMode3d. Estoy intentando utilizar un Lambda de hacerlo, es decir:.

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

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

A pesar de 6 DisplayMode3d de MyDisplayDevices en sólo 1 tiene cualquiera de DisplayMode3d en su colección modos, nada está siendo eliminado de la lista.

¿Qué error numpty he puesto aquí?

Editar:

Ah bien, mi error fue que debería usar MyDisplayDevices.remove_if en lugar de std :: remove_if, sin embargo, las respuestas a continuación son correctos para el uso de std :: remove_if:. P

MyDisplayDevices.remove_if( [](DisplayDevice3d const & device) 
                            { 
                                return device.Modes.size() == 0; 
                            });
¿Fue útil?

Solución

Es necesario llamar borrado en el iterador de regresar de remove_if, debe ser algo como esto:

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

MyDisplayDevices.erase(new_end, MyDisplayDevices.end());

Otros consejos

remove_if no quita nada de la lista sólo los mueve a fin. Es necesario utilizar junto con erase. Ver este pregunta para más detalles.

remove_if no realiza el cambio de tamaño, sino que simplemente devuelve el iterador al elemento que sigue al último elemento no se elimina. Este iterador se puede pasar a erase() hacer la limpieza.

 introducir descripción de la imagen aquí

Como otros han mencionado, hay maneras de hacer que funcione. Sin embargo, mi consejo sería evitar completamente remove_if y se adhieren a un estándar de eliminación basada en iterador lugar. El idioma más adelante obras tanto para list y vector y no produce un comportamiento inesperado.

for( vector<TYPE>::iterator iter = vec.begin() ; iter != vec.end() ; )
  if( iter->shouldRemove )
    iter = vec.erase( iter ) ; // advances iter
  else
    ++iter ; // don't remove

Como los comentarios a continuación mención, este método tiene un costo mayor que remove_if cuando se retira más de 1 elemento.

remove_if funciona copiando elementos de más adelante en el vector, y sobrescribir los vectores que deben ser eliminados a partir del vector por el inmediatamente en frente de ella. Por ejemplo: remove_if llamada en un vector para eliminar los 0 elementos:

0 1 1 0 1 0

resultados en:

1 1 1 0 1 0

Note como el vector no es correcto todavía. Esto se debe a remove_if devuelve un iterador para el último elemento válido ... que no cambia de tamaño automáticamente el vector. Todavía es necesario v.erase() llamada en el iterador de regresar de su llamada a remove_if.

Un ejemplo es inferior a

#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)
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top