Question

Ok, je pense que je l'ai fait une erreur stupide ici. J'ai une liste de DisplayDevice3d et chaque DisplayDevice3d contient une liste de DisplayMode3d. Je veux supprimer tous les éléments de la liste des DisplayDevice3d qui n'ont pas DisplayMode3d de. Je suis en train d'utiliser un Lambda pour le faire, à savoir:.

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

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

Bien que de 6 DisplayMode3d est dans MyDisplayDevices, seulement 1 a tout de DisplayMode3d dans sa collection Modes, rien est retiré de la liste.

Quelle erreur ont numpty je fait ici?

Edit:

Ah ok, mon erreur était que je devrais utiliser MyDisplayDevices.remove_if au lieu de std :: remove_if, mais les réponses ci-dessous sont correctes pour l'utilisation de std :: remove_if. P

MyDisplayDevices.remove_if( [](DisplayDevice3d const & device) 
                            { 
                                return device.Modes.size() == 0; 
                            });
Était-ce utile?

La solution

Vous devez appeler effacer le retour de iterator remove_if, il devrait ressembler à ceci:

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

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

Autres conseils

remove_if ne supprime rien de la liste, il suffit de les déplace à la fin. Vous devez l'utiliser avec erase. Voir cette question pour plus de détails.

remove_if ne fonctionne pas le redimensionnement, mais il retourne juste l'itérateur à l'élément qui suit le dernier élément non retiré. Ce iterator peut être transmis à erase() pour faire le nettoyage.

 entrer image description ici

Comme d'autres l'ont mentionné, il existe des moyens pour le faire fonctionner. Cependant, mon conseil serait d'éviter complètement remove_if et le bâton à une norme basée retrait iterator au lieu. L'idiome ci-dessous pour les deux œuvres list et vector et ne produit pas un comportement inattendu.

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

Comme les commentaires ci-dessous mention, cette méthode a un coût plus élevé que lorsque l'élément remove_if plus de 1 est supprimé.

remove_if fonctionne en copiant des éléments de plus loin dans le vecteur, et l'écrasement des vecteurs qui doivent être retirés du vecteur par l'une immédiatement en avant de celui-ci. Par exemple: remove_if appelé un vecteur pour supprimer tous les éléments 0:

0 1 1 0 1 0

résultats dans:

1 1 1 0 1 0

Remarquez comment le vecteur est pas encore correct. C'est parce que remove_if retourne un itérateur au dernier élément valide ... il ne redimensionne pas automatiquement le vecteur. Vous devez toujours appel v.erase() sur le iterator retour de votre appel à remove_if.

Un exemple est ci-dessous

#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)
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top