[C++/STL] Retrait d'un élément dans une list

Retrait d'un élément dans une list [C++/STL] - C++ - Programmation

Marsh Posté le 12-01-2004 à 21:29:13    

Le code suivant me pond une exception...
 

Code :
  1. list < Cmachin > Cmachin_list;


 

Code :
  1. for ( it = Cmachin_list.begin() ; it != Cmachin_list.end() ; ++it)
  2. {
  3.    if( qqchose_de_vrai )
  4.       Cmachin_list.erase(it);
  5. }


 
La boucle n'est peut etre pas la meilleure structure de contrôle pour réaliser le retrait d'un élément d'une liste. :non:  
 
Comment puis-je m'en sortir de manière plaisante ?
 
Merci d'avance,
   Xterm-in-hate.

Reply

Marsh Posté le 12-01-2004 à 21:29:13   

Reply

Marsh Posté le 12-01-2004 à 21:37:14    

rtfm
 
void remove(const T& val);
 
template<class Predicate>  
void remove_if(Predicate p);  
[4]

Reply

Marsh Posté le 12-01-2004 à 21:52:35    

Merci taz, mais j'ai pas encore décoder la totalité de ce que tu as écrit :)
 
D'aitre part, ci-joint l'aide dans la MSDN :
 
list::erase
iterator erase(iterator it);
iterator erase(iterator first, iterator last);
The first member function removes the element of the controlled sequence pointed to by it. The second member function removes the elements of the controlled sequence in the range [first, last). Both return an iterator that designates the first element remaining beyond any elements removed, or end() if no such element exists.
 
Erasing N elements causes N destructor calls. No reallocation occurs, so iterators and references become invalid only for the erased elements.
 
PAr conséquent, j'ai modifié mon code de la sorte :
 

Code :
  1. for ( it = Cmachin_list.begin() ; it != Cmachin_list.end() ; ++it)
  2. {
  3.   if( qqchose_de_vrai )
  4.      it = Cmachin_list.erase(it);  // erase() retourne le nouvel it valide (si j'ai bien capté)
  5. }

 
 
Je n'ai plus d'exception mais je ne suis pas sur que cela marche parfaitement...
 
Cordialement,
   Xterm-in-hate.

Reply

Marsh Posté le 12-01-2004 à 21:53:21    

putain mais lit pas la msdn pour STL
 
tu vas sur le site de SGI comme tout le monde :o

Reply

Marsh Posté le 12-01-2004 à 21:55:15    

Ca doit être mon profil "programmeur de fortran des années 50"... je suis pas encore tres familiarisé avec STL ;)
 
Xter.

Reply

Marsh Posté le 12-01-2004 à 22:04:33    

Mon code est sans doute foireux.
 
Erase() retourne un iterator valide qui suit l'element retiré de la liste. Puis, dans ma boucle for(), j'incremente l'iterator d'un élement.
 
Donc l'element de la liste qui suit l'élément retiré est systématiquement sauté... ca plante pas mais c est pas correct.
 
Cordialement,
   Xter.

Reply

Marsh Posté le 12-01-2004 à 22:08:47    

mais tu le fais exprès ou t'es capable de consulter la documentation de sgi et celle des fonctions membres remove et remove_if ?

Reply

Marsh Posté le 12-01-2004 à 22:18:13    

Je suis un peu sourd, tu fais bien d'insister !
 
Effectivement remove_if correspond exactement à ce que je recherche :) Par contre la syntaxe du Predicate ne m'est pas familière mais je devrais y arriver...
 
Merci,
   Xter.

Reply

Marsh Posté le 12-01-2004 à 22:26:49    

Je dirais même plus, elle est rudement balaise la syntaxe ! Ca me tue...

Reply

Marsh Posté le 12-01-2004 à 22:30:25    

tu comprends quoi ?

Reply

Marsh Posté le 12-01-2004 à 22:30:25   

Reply

Marsh Posté le 12-01-2004 à 22:36:19    

Comment puis-je faire pour transformer l'ecriture de ma condition if( qqchose) en un Predicate ?
 
Si tu as des exemples parlants des fonctions en XXXX_if(,, Predicate p ). Il semblerait qu'elles soient couplées avec l'appel de Bind1st ou Bind2nd ....
 
 
 

Reply

Marsh Posté le 12-01-2004 à 22:38:40    

template<class Predicate>  
void remove_if(Predicate p);
->
Removes all elements *i such that p(*i) is true.

Reply

Marsh Posté le 12-01-2004 à 22:38:44    

Oui, merci.
 
Predicate pourrait être une fonction qui retourne un BOOL... lol


Message édité par xterminhate le 12-01-2004 à 22:39:29
Reply

Marsh Posté le 12-01-2004 à 22:51:11    

pas BOOL, mais bool. et Predicate p est template et peut être n'importe quoi qui a un opérateur operator()(const T & ) const
 
donc fonction ou objet

Reply

Marsh Posté le 12-01-2004 à 23:23:32    

La fonction remove_if( start, end, predicate p) fonctionne parfaitement avec en argument une simple fonction qui retourne bool.
 
Par contre list.remove_if( predicate p) fonctionne differement et j'arrive à rien.
 
Dans Visual :
'remove_if' : cannot convert parameter 1 from 'bool (struct x_ClientSocket)' to 'class std::binder2nd<struct std::not_equal_to<struct x_ClientSocket> >'
 


Message édité par xterminhate le 12-01-2004 à 23:27:40
Reply

Marsh Posté le 12-01-2004 à 23:47:56    

donne du code

Reply

Marsh Posté le 12-01-2004 à 23:58:55    

Tout se déroule dans une classe nommée X_HttpServer.
 
La liste:

Code :
  1. typedef list< x_ClientSocket > x_ClientSocketList;
  2. x_ClientSocketList client_socket_list;


 
L'appel de std::list.remove_if() à partir d'une fonction membre de x_HttpServer:

Code :
  1. // Disconnect and remove client socket element
  2. client_socket_list.remove_if( ClientSocketDisconnectionTest );


 
La fonction membre de x_HttpServer qui réalise le test de l'élement de la liste a retirer :

Code :
  1. bool x_HttpServer::ClientSocketDisconnectionTest(x_ClientSocket cs)
  2. {
  3. // Local varaibles
  4. long current_time;
  5. // Obtain current time
  6. time( &current_time );
  7. // Return true if client socket must be disconnected
  8. return( ( ( !cs.bKeepAlive ) && ( ( current_time - cs.lLastRequestTime ) > cFirstRequestTimeOut ) ) ||
  9.      ( ( cs.bKeepAlive ) && ( ( current_time - cs.lLastRequestTime ) > cNextRequestTimeOut ) ) ||
  10.      cs.bForceDisconnection );
  11. }


 

Reply

Marsh Posté le 13-01-2004 à 00:42:18    

et elle à la tronche de ce qui est demandé ? non
c'est même pas synthaxiquement correct ton truc

Reply

Marsh Posté le 13-01-2004 à 00:47:33    

Oui je sais bien, mais je suis incapable de coder une fonction qui ait le format demandé ! Pour le moment... moi et STL c'est pas encore cà et j'apprends de manière empirique !
 
Pourtant,
 

Code :
  1. remove_if( client_socket_list.begin(), client_socket_list.end(), ClientSocketDisconnectionTEst );


 
fonctionne parfaitement. Mais ca ne modifie pas ma liste... evidemment !


Message édité par xterminhate le 13-01-2004 à 00:48:59
Reply

Marsh Posté le 13-01-2004 à 00:54:30    

Ben non y a pas de erase.
Mais bon pour les listes c'est plutôt
client_socket_list.remove_if(ClientSocketDisconnectionTEst );

Reply

Marsh Posté le 13-01-2004 à 00:59:52    

Exact mais encore faut il fournir à cette #?&! de fonction remove_if le bon argument à la sauce STL.

Reply

Marsh Posté le 13-01-2004 à 01:09:12    

xterminhate a écrit :

Exact mais encore faut il fournir à cette #?&! de fonction remove_if le bon argument à la sauce STL.  

1) c'est pas le bon type
2) je sais pas ou t'as vu qu'on se servait d'un pointeur de fonction membre comme ça
3) voir mes premiers messages

Reply

Marsh Posté le 13-01-2004 à 08:09:22    

SGI a dit :
 
Remove_if returns an iterator that points to the end of the resulting range after elements have been removed from it; it follows that the elements after that iterator are of no interest, and may be discarded. If you are removing elements from a Sequence, you may simply erase them. That is, a reasonable way of removing elements from a Sequence is ...

Code :
  1. S.erase(remove_if(S.begin(), S.end(), pred), S.end()).


 
Interessant ! Donc voici mon code et cela semble marcher correctement :
 

Code :
  1. client_socket_list.erase(remove_if( client_socket_list.begin() , client_socket_list.end(), ClientSocketDisconnectionTest ), client_socket_list.end() ) ;


 
Merci.

Reply

Marsh Posté le 13-01-2004 à 09:29:26    

masi c'est quoi ce bordel ?
 

Code :
  1. #include <iostream>
  2. #include <list>
  3. #include <algorithm>
  4. #include <iterator>
  5. #include <functional>
  6. int main()
  7. {
  8.   int data[13];
  9.   std::list<int> l(data, data + sizeof data / sizeof data[0]);
  10.   std::copy(l.begin(), l.end(), std::ostream_iterator<int>(std::cout, ", " ));
  11.   std::cout << '\n';
  12.   l.remove_if(std::bind2nd(std::modulus<int>(), 2));
  13.   std::copy(l.begin(), l.end(), std::ostream_iterator<int>(std::cout, ", " ));
  14.   std::cout << '\n';
  15.   l.remove_if(std::bind2nd(std::less<int>(),  0));
  16.   std::copy(l.begin(), l.end(), std::ostream_iterator<int>(std::cout, ", " ));
  17.   std::cout << '\n';
  18. }


 
après tu regarde si tu veux utilsez des fonctions membres liées (pas static), faut qu'elle soit const, ou mieux, qu'elles aient operator() const
 
après
 
l.remove_if(objet)
 
ou en compliqué
 
l.remove_if(boost::bind1st(boost::mem_fun_ref(&Greeter::hello), g))
 
 

Code :
  1. #include <boost/functional.hpp>
  2. #include <iostream>
  3. #include <algorithm>
  4. #include <string>
  5. struct Greeter
  6. {
  7.   Greeter(const std::string &n)
  8.     : name(n)
  9.   {}
  10.   void hello(const std::string &s) const
  11.   {
  12.     std::cout << this->name << " dit bonjour à " << s << '\n';
  13.   }
  14.   const std::string name;
  15. };
  16. int main()
  17. {
  18.  
  19.   const std::string tab[] = {"Porcinet", "Bouriquet", "Tigrou"};
  20.   Greeter g("Taz" );
  21.   std::for_each(tab, tab + sizeof tab / sizeof *tab, boost::bind1st(boost::mem_fun_ref(&Greeter::hello), g));
  22. }


 
mais comme tu vois faut passer par boost pour pallier a une inconsistence de STL dans sa version actuelle

Reply

Marsh Posté le 13-01-2004 à 10:11:24    

Attention à ne pas confondre la fonction membre list::remove avec l'algorithme remove.
 
Le premier retire effectivement les elements de la liste ce que ne fait pas l'algorithme remove. Si ton conteneur est une list, il est très très fortement conseiller de passer par list::remove. Dans tous les autres cas il faut faire le v.erase(remove ... indiqué

Reply

Marsh Posté le 13-01-2004 à 19:58:52    

C'est bete mais remove ne s'utilise pas aussi facilement que erase consécutivement à l'appel de remove_if.
 
Je vais devoir m'interesser à for_each de plus pres, ca a l'air pratique :-)
 
 
 

Reply

Marsh Posté le 13-01-2004 à 20:13:23    

euh tu fout quoi là sans déconner ? on te file la solution et tu perds ton temps avec du bordel qui fait pas bien le boulot

Reply

Marsh Posté le 13-01-2004 à 20:20:36    

On se calme :) Il me faut un peu de temps pour assimiler vos conseils.
 
Merci,
   Xter.

Reply

Marsh Posté le 13-01-2004 à 20:33:57    

bah non, tu t'égares. je te guide, exemple à l'appui et toi tu par dans une autre direction, mauvaise et lourde

Reply

Marsh Posté le 13-01-2004 à 23:33:34    

Pourquoi as tu besoin d'exploiter boost::, ces fonctions ne sont elle pas déjà définis dans STL ?

Reply

Marsh Posté le 13-01-2004 à 23:40:12    

il me semble que le bind de la STL a un problème


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 14-01-2004 à 00:14:02    

BlackGoddess a écrit :

il me semble que le bind de la STL a un problème

il est correct, mais la fonction n'est pas surchargé pour tous les cas de constness, etc, boost comble le fossé. boost est parfois plus standard que STL et sera en partie phagocytée

Reply

Marsh Posté le 14-01-2004 à 09:26:39    

Taz a écrit :

boost est parfois plus standard que STL et sera en partie phagocytée


 
j'ai deja lu ca :p


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 14-01-2004 à 17:47:11    

Tout arrive! J'ai enfin compris et fait trouner une fonction objet avec un for_each. Apres ca, je vais peut etre enfin arrivé à comprendre le std::list.remove_if() :)
 
Merci,
   Xter.

Reply

Marsh Posté le 14-01-2004 à 21:59:17    

Bon j'en suis là...
 
list.remove_if(p) : Removes all elements *i such that p(*i) is true
 
Je déclare un objet 'f' avec une fonction membre de telle sorte que f(*i) retourne un bool.
 
J'écrit :  

Code :
  1. list.remove_if(f);


 
Evidemment, cela ne passe pas. Un ptit indice pour m'aider dans la dernière ligne droite ? ;)

Reply

Marsh Posté le 14-01-2004 à 22:00:45    

f ne doit pas être une fonction membre. Sinon, pourquoi lui passer l'element à tester en paramètre.


Message édité par Kristoph le 14-01-2004 à 22:00:55
Reply

Marsh Posté le 14-01-2004 à 22:01:42    

Kristoph a écrit :

f ne doit pas être une fonction membre. Sinon, pourquoi lui passer l'element à tester en paramètre.

f peut être n'importe quoi tant que l'appelle va
 
du code bordel. toute une page, on en est revenu au point de départ

Reply

Marsh Posté le 14-01-2004 à 22:04:51    

Code :
  1. // Function Object
  2. template <class x_ClientSocket>
  3. class fTestClientSocketClosed: public std::unary_function< x_ClientSocket, bool >
  4. {
  5. public:
  6.  fTestClientSocketClosed() { }
  7.  bool operator()( const x_ClientSocket & cs ) const { return cs.bClosed; }
  8. };


 
puis
 

Code :
  1. fTestClientSocketClosed <x_ClientSocket> ftcsc ;
  2. client_socket_list.remove_if(ftcsc);


Reply

Marsh Posté le 14-01-2004 à 22:16:40    

tu le fais expres avec tes noms de paramètres templates ou quoi ?
 

Code :
  1. #include <list>
  2. struct Foo
  3. {
  4.   bool operator()(int i) const
  5.   {
  6.     return i;
  7.   }
  8. };
  9. int main()
  10. {
  11.   std::list<int> l;
  12.   Foo f;
  13.   l.remove_if(f);
  14. }

Reply

Marsh Posté le 14-01-2004 à 22:23:50    

Bon on doit pas avoir le meme compiloe, car on a ecrit la même chose et chez moi rien ne passe.
 
Visual Touch....

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed