Ok, je suppose que j'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 de DisplayMode3d. J'essaie d'utiliser une Lambda pour le faire, c'est-à-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;
}
);
Même si sur 6 DisplayMode3d dans MyDisplayDevices, seulement 1 a des DisplayMode3d dans sa collection Modes, rien n'est supprimé de la liste.
Quelle erreur vide j'ai fait ici?
Éditer:
Ah ok, mon erreur était que je devrais utiliser MyDisplayDevices.remove_if au lieu de std :: remove_if, cependant 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;
});
Vous devez appeler erase sur l'itérateur renvoyé par 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());
remove_if
ne supprime rien de la liste, il les déplace simplement vers la fin. Vous devez l'utiliser avec erase
. Voir ceci question pour plus de détails.
Comme d'autres l'ont mentionné, il existe des moyens de le faire fonctionner. Cependant, mon conseil serait d'éviter complètement remove_if
Et de s'en tenir à une suppression basée sur un itérateur standard à la place. L'idiome ci-dessous fonctionne à la fois pour list
et vector
et ne produit pas de 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 le mentionnent les commentaires ci-dessous, cette méthode a un coût plus élevé que remove_if
Lorsque plus d'un élément est supprimé.
remove_if
Fonctionne en copiant les éléments de plus loin dans le vecteur et en écrasant les vecteurs qui devraient être supprimés du vecteur par celui qui se trouve juste devant lui. Par exemple: remove_if appelé sur un vecteur pour supprimer tous les 0 éléments:
0 1 1 0 1 0
résulte en:
1 1 1 0 1 0
Notez que le vecteur n'est pas encore correct. C'est parce que remove_if
Renvoie un itérateur au dernier élément valide ... il ne redimensionne pas automatiquement le vecteur. Vous devez toujours appeler v.erase()
sur l'itérateur renvoyé 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)
}