Domanda

Ok, mi aspetto che ho fatto un errore stupido qui. Ho una lista di DisplayDevice3d e ogni DisplayDevice3d contiene un elenco di DisplayMode3d. Voglio rimuovere tutti gli elementi dalla lista dei DisplayDevice3d che non hanno alcun DisplayMode3d di. Sto cercando di utilizzare un Lambda per farlo, vale a dire:.

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

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

Anche se su 6 DisplayMode3d di in MyDisplayDevices, solo 1 ha qualche DisplayMode3d di nella sua collezione Modi, nulla è stato rimosso dalla lista.

Cosa numpty errore hanno ho fatto qui?

Modifica:

Ah ok, il mio errore è stato dovrei usare MyDisplayDevices.remove_if invece di std :: remove_if, tuttavia le risposte che seguono sono corrette per l'utilizzo di std :: remove_if:. P

MyDisplayDevices.remove_if( [](DisplayDevice3d const & device) 
                            { 
                                return device.Modes.size() == 0; 
                            });
È stato utile?

Soluzione

È necessario chiamare cancellazione sull'iteratore tornato da remove_if, Dovrebbe essere qualcosa di simile:

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

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

Altri suggerimenti

remove_if non toglie nulla dalla lista semplicemente li muove alla fine. È necessario utilizzare insieme con erase. Vedere questo domanda per ulteriori dettagli.

remove_if non esegue il ridimensionamento, ma invece è solo restituisce l'iteratore all'elemento che segue l'ultimo elemento non rimosso. Questo iteratore può essere passato a erase() per fare la pulizia.

 entrare descrizione dell'immagine qui

Come altri hanno detto, ci sono modi per farlo funzionare. Tuttavia il mio consiglio è di evitare completamente remove_if e bastone per una rimozione standard di iteratore-based, invece. L'idioma di seguito opere sia per list e vector e non produce un comportamento imprevisto.

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

Come commenti sotto menzione, questo metodo ha un costo superiore remove_if quando più di 1 elemento viene rimosso.

remove_if funziona copiando elementi più avanti nel vettore, e sovrascrivendo i vettori che dovrebbero essere rimossi dal vettore per quello immediatamente di fronte ad essa. Ad esempio: remove_if invitato un vettore per rimuovere tutti i 0 elementi:

0 1 1 0 1 0

Risultati in:

1 1 1 0 1 0

Si noti come il vettore non è corretta ancora. Questo perché remove_if restituisce un iteratore per l'ultimo elemento valido ... non ridimensiona automaticamente il vettore. Hai ancora bisogno di chiamata v.erase() sull'iteratore restituita dalla chiamata a remove_if.

Un esempio è inferiore 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)
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top