Question

J'écris un programme qui est plus ou moins comme ceci:

#include <list>

list<MyClass> things;

class MyClass {
   // some stuff

   void remove() {
       things.remove_if(THING_IS_ME);
   }
};

Que dois-je écrire au lieu de THING_IS_ME?

En d'autres termes, j'utilise une liste globale de STL comme une collection de choses. À un certain moment, un objet qui est dans la liste reconnaît qu'il est redondant et veut a) obtenir lui-même retiré de la liste, et b) obtenir lui-même DESTRUCTED.

Comment puis-je faire?

Je n'ai pas écrit en C ++ depuis environ 15 ans et je suis un peu confus par cette page ici: http://www.cplusplus.com/reference/algorithm/remove_if/

Quels sont ces prédicats? Est-ce que C ++ ont des fonctions d'ordre supérieur maintenant?

Était-ce utile?

La solution

(origine un ensemble de commentaires, mais réécrite comme une réponse après avoir découvert ce que l'OP voulait réellement faire.)

Vous vous rendez compte que les conteneurs STL magasin copies de choses que vous insérez, non? Cela signifie que les cas de MyClass mieux être comparables (par exemple via operator==) -. Vous ne pouvez pas comparer les adresses car ils seront toujours différents

Si avoir des copies de MyClass n'a pas de sens, alors vous êtes probablement mieux avec un récipient de pointeur .

Cela étant dit, les utilisations du langage C de copie sémantique par défaut. La langue exige que vous faites des choses comme des références explicites dans le code. Je recommande fortement que vous prenez un bon C ++ livre ou vous être déclenché par des problèmes comme celui-ci à l'avenir.

Autres conseils

Les choses ont changé de façon spectaculaire en C ++ au cours des 15 dernières années. En Juillet 1994 Alexander proposition de Stepanov d'une bibliothèque qui intègre ses idées de programmation générique reçu l'approbation finale du comité ANSI / ISO. Cette bibliothèque que nous appelons aujourd'hui commodément le TSL est devenu par la suite une bibliothèque standard C ++. L'histoire du TSL est à peu près aussi fascinant que les idées derrière, et il vaut vraiment la peine d'être lu.

La fonction std::remove_if() que vous avez trouvé est juste une autre reflet de cette philosophie qui fait partie de l'identité moderne de C ++. Bref, cela est une fonction générique qui fonctionnera sur tout récipient (séquence) d'éléments et toute (chose qui agit comme un) état. A cet effet, vous devez fournir la fonction de deux choses:

  1. deux itérateurs qui délimitent la plage d'éléments que vous souhaitez travailler;
  2. et prédicat qui, lorsqu'il est appelé sur un élément, renvoie true si l'élément doit être enlevé et faux autrement.

Il se trouve que, dans ce cas, le prédicat que vous voulez est celui de l'égalité. Et parce qu'il est une tâche commune aux éléments remove fondée sur l'égalité de la norme prévoit également la fonction std::remove(), qui suppose un prédicat d'égalité implicite. Bien sûr, vous devez vous assurer que les éléments peuvent comparer:

bool operator==(const MyClass& a, const MyClass& b)
{
    // return true if the two are equal, and false otherwise.
}

On peut alors utiliser notre prédicat pour supprimer des éléments de type MyClass:

std::remove(things.begin(), things.end(), *this);  // if *this == elem

Rappelez-vous que la std::remove() fonction standard fonctionne sur any conteneur, ceux même qui n'ont pas encore été créé. Parce que chaque type de conteneur a sa propre façon d'enlever des éléments, cette fonction ne peut pas vraiment effectuer le retrait sans connaître les détails de mise en œuvre du récipient, il fonctionne sur. Ainsi, au lieu, les éléments de swaps de fonction std::remove() autour de telle sorte que les éléments « enlevés » sont à la fin du récipient. Puis, elle renvoie un itérateur pointant sur le premier élément des éléments consécutifs « supprimé ».

typedef std::list<MyClass>::iterator iter;
iter first_removed = std::remove(things.begin(), things.end(), *this);

Enfin, nous supprimons vraiment des éléments en appelant la fonction de suppression du conteneur spécifique, qui travaille sur une seule position dans la liste ou sur une série d'éléments consécutifs à supprimer:

things.erase(first_removed, things.end());

Il est pas rare de voir ce genre de code dans une seule ligne:

things.erase(std::remove(things.begin(), things.end(), *this),
             things.end());

Tout cela peut sembler écrasante et compliqué, mais il a quelques avantages. D'une part, cette conception de la bibliothèque standard prend en charge la programmation dynamique. Il permet également la bibliothèque standard de conteneurs offre avec des interfaces très minces, ainsi que quelques fonctions libres que le travail sur différents types de conteneurs. Il vous permet de créer rapidement un conteneur et gagnez instantanément toutes les fonctionnalités de la bibliothèque standard pour travailler avec elle. Sinon, il vous permet d'écrire rapidement une fonction générique qui fonctionne instantanément avec tous les conteneurs standards -. Ceux écrits déjà et ceux pas encore écrit

Tout d'abord, un simple boucle écrite à la main:

for( list<MyClass>::iterator it = things.begin(); it != things.end(); /*  */ ) {
    if( qualifiesForDelete( *it ) ) {
        it = things.erase( it );
    }
    else {
        ++it;
    }
}

En second lieu, en utilisant l'algorithme de remove_if. remove_if étant un algorithme, par opposition à une fonction membre de list, ne peut pas supprimer en fait tous les éléments, mais plutôt déplace les éléments-à-être-supprimé à la fin de la liste. Par la suite erase doit être appelé. Ce langage est un très important, effacement supprimer idiome , qui doit être appris.

things.erase( 
    remove_if( things.begin(), things.end(), deletionPredicate ), 
    things.end() 
);

deletionPredicate est une fonction ou une fonction-objet qui prend un seul argument de type et retourne bool. Les éléments pour lesquels true est renvoyé sont considérés comme retirés.

La fonction remove_if prend trois paramètres: deux itérateurs qui définissent la plage que vous travaillez sur, et un prédicat (fonction de test que les rendements bool). Le début iterator des points au premier élément que vous voulez travailler; les points d'itérateur d'extrémité à l'élément après le dernier élément de la série.

Dans l'exemple de la page lié à , le prédicat est la ligne du code qui dit

bool IsOdd (int i) { return ((i%2)==1); }

Pour faire votre code faire ce que vous voulez, vous aurez besoin de quelque chose écrire comme ceci:

things.remove_if(things.begin(), things.end(), SomePredicateFunction);

et que vous définissez SomePredicateFunction comme si (remplaçant true par un test approprié):

bool SomePredicateFunction (MyClass c) { return true; }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top