IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Affichage des résultats du sondage: Utilisez-vous les algorithmes de la STL en 2012 ?

Votants
114. Vous ne pouvez pas participer à ce sondage.
  • Jamais, je les connais pas.

    26 22,81%
  • Jamais, je les aime pas.

    3 2,63%
  • Exceptionnellement.

    16 14,04%
  • Occasionnellement.

    31 27,19%
  • Les plus souvent possible.

    39 34,21%
  • Toujours.

    3 2,63%
  • Toujours à partir de maintenant, je vais appliquer ta règle.

    0 0%
Sondage à choix multiple
C++ Discussion :

Faut-il bannir le for du C++ ? [Débat]


Sujet :

C++

  1. #81
    Membre éprouvé

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Points : 1 086
    Points
    1 086
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Je me demandais, est-il possible avec une telle écriture (for range loop, foreach, ...) de réaliser un break et sortir de la boucle plus tôt ?
    Bien que je suppose qu'il s'agisse d'une mauvaise pratique.
    Ça dépend du rôle du break dans la boucle for.
    Souvent, il s'agit de parcourir des éléments jusqu'à ce que l'un réponde à une condition/un prédicat. Dans ce cas-là, un std::find_if peut suffire.

  2. #82
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Effectivement c'est le cas le plus courant.

    Mais une autre utilisation m'interpelle:
    quid de réaliser une action sur un élément externe : faire une somme des éléments, remplir un autre tableau qu'on utilisera en sortie de boucle ?
    Jusqu'à présent tous les exemples montrent l'utilisation de l'élément actuellement parcouru sans action sur un élément externe à lui-même.

    Utiliser for_each avec une classe qui enregistre le résultat en membre sur lequel réaliser un get à la fin ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // for_each example
    #include <iostream>
    #include <algorithm>
    #include <vector>
    using namespace std;
     
    struct somme {
      myclass() : result(0) {}
      void operator() (int i) { result += i; }
      int result;
    };
     
    int main () {
      vector<int> myvector;
      myvector.push_back(10);
      myvector.push_back(20);
      myvector.push_back(30);
     
      somme myobject;
      for_each (myvector.begin(), myvector.end(), myobject);
     
      cout << myobject.result << endl;
     
      return 0;
    }
    ? D'après l'exemple fourni sur http://www.cplusplus.com/reference/algorithm/for_each/
    Je trouve ça un peu lourd comme opération. Enfin ces "soucis" de lourdeur sont en grande partie améliorés par les lambdas (vivement que je puisse les utiliser )
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #83
    Membre éprouvé

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Points : 1 086
    Points
    1 086
    Par défaut
    Dans ce cas-là on s'intéressera plutôt à std::accumulate avec std::plus<int>() comme BinaryOp.

  4. #84
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Je me demandais, est-il possible avec une telle écriture (for range loop, foreach, ...) de réaliser un break et sortir de la boucle plus tôt ?
    Bien que je suppose qu'il s'agisse d'une mauvaise pratique.
    A priori, ce n'est pas possible,étant donné qu'elles sont clairement prévues pour itérer sur l'ensemble de l'intervalle [begin ] end, du moins, dans celles que tu cites

    De plus, mais ce n'est qu'un avis perso, je n'ai jamais aimé devoir recourir à un break ou à un continue dans une boucle, et j'ai toujours préféré, à ce moment là, utiliser une variaboe qui indique clairement la raison pour laquelle on continue (ou pour laquelle on sort de la boucle), et l'introduire dans la condition d'entrée (ou de sortie, selon le cas), quitte à changer de style de boucle, ou à placer un test qui évitera l'exécution d'une partie de code si certaines conditions ne sont pas remplies

    J'avoue cependant bien volontiers que c'est fortement inspiré de la méthode que je préfère pour envisager mes algorithmes (le nassi-schneidermann, pour ne pas le citer)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #85
    Membre éprouvé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2006
    Messages
    519
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Septembre 2006
    Messages : 519
    Points : 1 104
    Points
    1 104
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Effectivement c'est le cas le plus courant.

    Mais une autre utilisation m'interpelle:
    quid de réaliser une action sur un élément externe : faire une somme des éléments, remplir un autre tableau qu'on utilisera en sortie de boucle ?
    Jusqu'à présent tous les exemples montrent l'utilisation de l'élément actuellement parcouru sans action sur un élément externe à lui-même.

    Utiliser for_each avec une classe qui enregistre le résultat en membre sur lequel réaliser un get à la fin ?
    C++11 dispose maintenant de fonctions lambda avec fermeture :

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cstdlib>
     
    int main() {
        std::vector<int> myvector;
        myvector.push_back(10);
        myvector.push_back(20);
        myvector.push_back(30);
     
        int somme;
        for_each(myvector.begin(), myvector.end(), [&somme](int x) {
            somme += x;
        });
     
        std::cout << somme << std::endl;
     
        return EXIT_SUCCESS;
    }

    Mais de toute façon, cob59 a raison quand il parle de std::accumulate.

  6. #86
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Par exemple les commentaires décrivent non pas ce que fait le code, mais ce que la personne l'ayant écrit croyait qu'il faisait. (...)

    Mais surtout pour moi les commentaires les plus intéressants sont ceux qui sont donnés non pas par // ou /* */ mais par des noms de variables ou de fonctions expressifs.
    Ne devrait-on pas faire à ces noms expressifs le même procès qu'aux commentaires? Un nom de variable, ou de fonction, ne représente que l'idée que le programmeur qui l'a choisi s'en faisait (souvent avant d'écrire le code, alors que le commentaire est écrit après). Et si le programmeur ne met pas à jour ses commentaires, comment espérer qu'il le fasse avec ses noms de fonctions ou de variables, tâche plus délicate?

    Ca nous ramène à l'expressivité des algorithmes. A moins d'utiliser des lambdas partout (ce qui n'est possible que pour de petites fonctions, et ne clarifie pas forcément le code), elle est directement fonction de la qualité du nom choisi pour la fonction qu'on leur passe.

    Rien que dans la STL, les exemples de nommage trompeurs existent. Qui ne s'est pas fait prendre par le fait que remove n'enlève rien, mais "selectionne" les éléments vérifiant une condition? que search trouve l'élément recherché, alors que binary_search n'est qu'un test d'existence? que inner_product n'est pas forcément un produit, ni partial_sum une somme? Et on parle ici d'une bibilothèque standard, écrite par des pros. Que penser de nos codes en "franglais de programmeur", ou de bibliothèques écrites par des programmeurs très doués, mais dont l'anglais n'est pas forcément la matière forte?

    Au final, même si, comme tout le monde, j'essaie de "nommer expressif", je me demande souvent si c'est une si bonne idée que cela. Un nom mal choisi (ou mal compris par celui qui le lira) est nettement plus dangereux, au fond, qu'on code un peu plus difficile à lire, mais qui ne pourra induire en erreur.

    J'observe d'ailleurs que pas mal de textes de référence (en algorithmique notamment) proposent un code bien peu expressif...

    Francois
    Dernière modification par Invité ; 05/04/2012 à 22h31.

  7. #87
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    199
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 199
    Points : 106
    Points
    106
    Par défaut
    Tant que l'on est autour du parcourt dans la boucle for, quelqu'un peut-il m'expliquer l’intérêt de boost.range par rapport à ce qu'il existe déjà?

    Dans l'overview :
    The motivation for the Range concept is that there are many useful Container-like types that do not meet the full requirements of Container, and many algorithms that can be written with this reduced set of requirements. In particular, a Range does not necessarily

    - own the elements that can be accessed through it,
    - have copy semantics,
    Également si celles-ci (ceux-ci ?), apportent beaucoup? Car elles nécessitent de réécrire les aglo standard non? Vaut mieux-t-il les utiliser?

    Merci

  8. #88
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Pour boost::range, utilises le une fois et tu verras comme c'est commode à utiliser.

    Par exemple (tiré de la doc) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    boost::push_back(
      vec
      , rng 
        | boost::adaptors::replaced_if(pred, new_value)
        | boost::adaptors::reversed);
    Insert à la fin de vec les éléments de rng en remplacant les valeur qui respectent le prédicat par new_value et en commencant par la fin (de rng).

    Une autre solution pour faire ca est de coder la boucle en dur (for ou for_each, peu importe), mais je doute que je soit réelement plus lisible. Ou alors d'utiliser un "Iterator Adaptator" qui rendra le for/for_each plus lisible mais sera aussi inutilement plus verbeux que boost::range (faudra écrire deux fois les "Iterator Adaptator" et ils s'echainent beaucoup moins naturellement que les "Range Adaptors").

    Je pense que ca fait partie des éléments de boost dont on a très facilement envie de le réutiliser une fois qu'on l'a testé.

    Pour les algos standards, ils sont déjà réécrit, donc tu n'as rien à réécrire.

    PS: Je reviens pas sur le fait que le concept de Range est bien plus large que celui de Containor comme l'indique la doc de boost. Il me semble aussi que tu dois pouvoir trouver des message de Alexandrescu expliquant la force des range par rapport aux itérateurs.

  9. #89
    Membre émérite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2008
    Messages
    832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 832
    Points : 2 625
    Points
    2 625
    Par défaut
    C'est marrant tout de même.

    Les anti-algo-stl de ce post semblent avoir oublié un détail énorme.
    La boucle for permet d'itérer dans un ordre précis une somme d'élément.

    Cette boucle for classique est donc le pendant de for_each.
    Enfin, pas tout à fait. En effet, for_each ne peut pas modifier la collection elle-même: uniquement ses éléments.

    Si l'ordre n'a aucune importance, genre charger N plug-ins dans un système simple (ou il n'y à pas de dépendances inter-plugin en fait), utiliser transform prend son intérêt.
    Parce que, selon la norme, transform ne garantit pas l'ordre de traitement. Et le code exécuté par transform ne doit pas avoir d'effets de bord (c'est transform qui a ces effets de bord, par le retour de la fonction qu'il exécute).

    Bon, c'est sûr, il faut s'intéresser à la doc. Mais quand on me parle de C#, je dois souvent reprendre la personne avec un truc du genre "Tu parles pas de C# la, mais de .NET.". Pour JAVA, c'est la même. Les gens d'aujourd'hui (en tout cas ceux avec qui je peux discuter) confondent langage et framework, et ce qui fait la réputation du manque de productivité de C++ est son framework standard limité. Alors qu'il s'agit du langage le moins limité j'ai l'impression. En C++, Qt (par exemple) refait tellement de mécanismes qu'il s'agit presque d'un langage différent (d'ailleurs, ils vont jusqu'a modifier la chaîne de compilation avec leur moc. Un peu comme le faisait CFront.)
    C++11 corrige justement une partie de ce problème, tout en conservant la puissance ancestrale qu'il à héritée du C (et l'absence d'interface graphique ^^).
    FOR ne dois pas disparaître, on en a besoin pour implémenter certains algos. Et GOTO ne doit pas disparaître non plus, on ne sait jamais, peut-être que certains s'en servent. N'empêche, 90% des boucles for classiques peut sûrement sauter, en faveur du "for(auto i:truc)" (qui, d'ailleurs, EST UN for spécialisé pour traiter la majorité des cas).
    Et dans ces 90% un certain nombre pourrait être remplacé par les algos.

    Honnêtement, les algos, je galère à m'en servir dans des cas qui sortent des cas d'école quand même.
    Par exemple, une fonction à 2 arguments. On peut la réduire avec des bind1st/bind2nd, c'est vrai (je ne connaît pas encore le bind tout court). Sauf que je n'arrive pas à utiliser ces binders avec les lambda (je suis en train de découvrir ce type de constructions, je dois rater un truc)?
    Et si le d'aventure le conteneur contient des unique_ptr, et qu'on cumule ces 2 problèmes, alors même avec une fonction écrite séparément, je n'y arrive pas. Du coup les algos sont certes plus utilisables qu'en C++03, mais ne restent pas aisés à manipuler pour moi.

    Pour en revenir à 2-3 trucs lus:
    Citation Envoyé par shenron666 Voir le message
    Quelqu'un peut me donner l'équivalent de ceci avec la stl ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for(int i=0; i < myArray.Count; ++i)
        myArray[i] = GenerateSomething(myArray[i], i);
    histoire de savoir si c'est possible avec autant voire moins de code
    Je pense que la méthode GenerateSomething est probablement juste mal conçue. Si elle prenait juste l'élément à modifier, avec les algo, ça donnerait ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Elem GenerateSomething(Elem &elem);
    foo()
    {
    transform(myArray.begin(),myArray.end(),myArray.begin(),&GenerateSomething);
    }
    A noter, d'ailleurs, qu'il serait possible d'ajouter l'attribut const au paramètre, et ainsi permettre d'assurer que la donnée du 1er tableau ne serait pas modifiée par la fonction. Conséquence, ça pourrait ainsi permettre de remplir un autre tableau avec le résultat, avec la garantie d'une source inviolée.
    Et ce code, si transform est codé pour être utilisé en thread, sera même plus rapide.

    2nd:
    Citation Envoyé par cob59 Voir le message
    Ça dépend du rôle du break dans la boucle for.
    Souvent, il s'agit de parcourir des éléments jusqu'à ce que l'un réponde à une condition/un prédicat. Dans ce cas-là, un std::find_if peut suffire.
    En fait, souvent, le break sert à identifier à quel élément on s'arrête. Ici, il est vrai que la solution STL que je vois (je ne suis pas du tout un expert, je galère comme un fou dès qu'il faut utiliser plus d'un argument, surtout avec les lambda, j'ai pas encore bien pigé la syntaxe) consomme plus de cycles processeurs dans le cas de conteneurs non triés, mais elle à l'avantage de permettre une meilleure atomicité des opérations dans certains cas (si l'ordre d'exécution n'est pas important, la majorité de mes boucles for, perso) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    auto it_first=find_if(array.begin(),array.end(),predicateFirst);
    auto it_last=find_if(it_first,array.end(),predicateLast);
    for_each(it_first,it_last, someWork);
    Bon, naturellement, on peut n'utiliser qu'un seul itérateur de limite (plus courant je pense).

    Toujours évidemment, dans certaines situations, il y a au moins une partie de boucle supplémentaire inutile (entre it_first et array.end() en fait).
    La situation en question est celle ou un conteneur non trié est utilisé. Dans l'autre cas, la complexité varie selon l'endroit ou se situe le dernier élément. Du coup, on peut avoir une optimisation en nombre de cycles.

    Il y a aussi le cas de l'utilisation de transform, qui peut permettre au compilateur d'optimiser, selon ce que fait someWork, pour le multi-thread.

    En fait, dans les cas ou au moins une de ces choses est vérifiées:
    _ un utilise une liste non triée
    _ l'ordre des opération est important
    _ someWork a des effets de bord
    Il est probablement plus efficace de coder dans la boucle même le "break".
    A noter que dans les cas ou l'on veut juste sauter un élément non valide (par exemple), on peut toujours utiliser ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    for_each(array.begin(),array.end(),someWork);
    avec someWork qui fait un vulgaire "if(do_I_continue)return;"

  10. #90
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Par exemple, une fonction à 2 arguments. On peut la réduire avec des bind1st/bind2nd, c'est vrai (je ne connaît pas encore le bind tout court). Sauf que je n'arrive pas à utiliser ces binders avec les lambda (je suis en train de découvrir ce type de constructions, je dois rater un truc)?
    Je n'ai pas compris pourquoi tu veux utiliser les bind avec des lambda? La capture du lambda fait le boulot pour toi, bind est obsolete...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
     
    std::function< void () > do_it_later( std::function<void ( int, const std::string& ) func, int i, const std::string& s )
    {
     
        return [=]   // capture toutes les variables utilisées dans la lambda par copie
                 // liste d'arguments optionelle, implicitement vide: ()
                 { f( i, s ); } // appelle donc les copies d i et s qui ont les valeurs de ces variables au moment de la creation de cette lambda
        ;
    }
     
     
     
    void do_something( std::function<void ( int, const std::string& ) func )
    {
           auto todo = do_it_later( func, 4, "Hello World" );
     
           // do something else
     
           todo(); // call func( 4, "Hello World" );
    }
    Code non testé mais c'est pour vérifier si j'ai bien compris de quoi tu parles?

  11. #91
    Débutant
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    688
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 688
    Points : 176
    Points
    176
    Par défaut
    quel est fondamentalement la différence entre utiliser for_each et une boucle for ? il n'y en a pas, c'est une question de goût. Tout ceci ressemble à de la masturbation intellectuelle.

  12. #92
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Il y en a, lis la discussion.

  13. #93
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    Les GotW en parlaient déjà en 1997 dès l'issue #3.
    La conclusion (pour ceux qui ont la flemme de le lire):
    [Guideline] Reuse standard library algorithms instead of handcrafting your own. It's faster, easier, AND safer!

  14. #94
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Cela dit, sans lambda il est raisonnable de considérer l'utilisation de certains de ces algorithms comme fastidieux a utiliser.

    Maintenant, si on a accès à un compilateur récent, il n'y a plus vraiment d'autre excuse que l'ignorance de l'existance des algorithmes pour ne pas les utiliser lorsqu'ils sont l'outil adéquate (c a d pas quand on a une boucle particulière à écrire, en suivant les prioriétés de choix recommandés dans cette discussion).

  15. #95
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par CedricMocquillon Voir le message
    Les GotW en parlaient déjà en 1997 dès l'issue #3.
    La conclusion (pour ceux qui ont la flemme de le lire):
    Les GotW parlent de find(), ce qui est assez différent, je crois, de l'idée proposée de supprimer les boucles en les remplaçant par des algorithmes appelant des foncteurs (ou des lambdas, ce qui revient exactement au même : un lambda c'est juste un "foncteur local"). Dans le premier cas, l'algorithme fait exactement le travail demandé, ne pas l'utiliser est absurde (même si le risque encouru en écrivant sa boucle à la main n'est pas bien grand...).

    Dans le second, on remplace une syntaxe classique par une de plus haut niveau, mais il reste toute la logique à écrire. Il y a matière à débat (et je suppose que c'est pour cela que ce fil est un "débat" et pas une entrée de FAQ)



    Ceci dit, dans le cas de find(), la "guideline" me parait très mauvaise. find() est un algorithme linéaire, il sera inefficace sur tout conteneur trié (cas très fréquent). Et le problème sera plus visible avec une boucle codée à la main qu'avec find(), qui cache son implémentation. Ca nous ramène au débat : utiliser un algorithme "parce que" c'est un algorithme, c'est presque toujours une mauvaise idée.

    Quant au GotW 2 auquel il est fait référence, j'avoue avoir souri en lisant:

    3. This one was more subtle. Preincrement is more efficient than postincrement, because for postincrement the object must increment itself and then return a temporary containing its old value. Note that this is true even for builtins like int!
    Ben tiens! A croire que les compilateurs optimisants n'existaient pas en 97...

    Francois
    Dernière modification par Invité ; 08/04/2012 à 15h08.

  16. #96
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    J'utilise souvent find avec des vecteurs d'objets non triés. Je n'ai jamais eu d'experiences où c'était fréquent...

    Donc je ne suis pas d'accord avec le fait que find soit inefficace, c'est exactement l'outil nécessaire pour pas mal de choses, même si ce n'est pas les cas les plus fréquents pour toi, ça l'est pour quelqu'un d'autre.

    Même chose pour les algos relatifs aux heap, que j'utilise rarement mais qui sont beaucoup utilisés dans certains domaines assez généralistes.

  17. #97
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Klaim Voir le message
    Donc je ne suis pas d'accord avec le fait que find soit inefficace, c'est exactement l'outil nécessaire pour pas mal de chose
    Je ne dis pas le contraire. find() est une recherche linéaire, elle sera optimale partout où la recherche linéaire est optimale, et inefficace partout ailleurs. C'est exactement ce qui m'ennuie avec la remarque du GotW, car elle peut laisser penser (et on observe dans des commentaires lus sur ce forum et ailleurs, comme dans du code réel, que certains le pensent effectivement) qu'un algorithme sera "toujours" plus efficace qu'un code fait main.

    Un exemple très clair est celui des tris. sort() est un dérivé de quicksort, il a ses conditions d'application, qui sont très larges, et certains cas où il n'est pas efficace (par exemple, celui d'un grand tableau prenant un petit nombre de valeurs, il faut alors un bucket sort, ou alors d'un tableau presque trié, ou un tri par insertion gagne toujours).

    Sur le caractère plus ou moins fréquent des conteneurs triés, c'est à mon avis un choix de conception. J'ai très souvent des conteneurs triés, parce que je constate que dès qu'on cherche plusieurs fois dans un conteneur, il devient intéressant de le trier. Un tri étant O(n log n) et une recherche linéaire N/2 si fructueuse, N si infructueuse, il est rentable de trier dès qu'on a plus d'une dizaine de recherches à faire. Ceci reste vrai, d'ailleurs, si on ajoute de temps en temps des éléments au conteneur (à condition de ne pas utiliser sort() pour le retrier).

    Francois
    Dernière modification par Invité ; 08/04/2012 à 16h01.

  18. #98
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    Pour le std::for_each, l'unique avantage est d'éviter d'oublier de stocker l'itérateur de fin (et d'éviter de nombreux appels à end()).
    Je t'accorde que c'est assez limité.
    Pour la guideline elle reste valable:
    - si tu as un vecteur trié, tu vas utiliser un std::lower_bound pour trouver l'élément cherché (à moins que tu ne recodes à chaque fois une recherche logarithmique)
    - si tu as une map ou un set, tu vas utiliser la méthode de classe fournie par la STL.
    Dans les deux cas, tu n'as pas besoin de réécrire quoi que ce soit.

  19. #99
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par CedricMocquillon Voir le message
    - si tu as un vecteur trié, tu vas utiliser un std::lower_bound pour trouver l'élément cherché (à moins que tu ne recodes à chaque fois une recherche logarithmique)
    - si tu as une map ou un set, tu vas utiliser la méthode de classe fournie par la STL.
    Oui, en fin de compte, on va utiliser find() pour un vecteur non trié ou une liste, lower_bound() pour un vecteur trié, une fonction membre pour les map, set et conteneurs hachés, et... je ne suis pas certain quoi, pour les multimap et multiset. Ceci veut dire que si l'implémentation change (ou le fait qu'un conteneur non trié le devienne), il faudra changer l'algorithme. En pratique, ca veut surtout dire que pas mal de programmeurs utiliseront find(), et s'étonneront de la lenteur de leur code.

    C'est exactement ce qui me fait dire que find() est peut être le plus mauvais exemple qu'on puisse prendre pour dire qu'il faut préférer les algorithmes.

    Francois

  20. #100
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Oui, en fin de compte, on va utiliser find() pour un vecteur non trié ou une liste, lower_bound() pour un vecteur trié, une fonction membre pour les map, set et conteneurs hachés, et... je ne suis pas certain quoi, pour les multimap et multiset. Ceci veut dire que si l'implémentation change (ou le fait qu'un conteneur non trié le devienne), il faudra changer l'algorithme. En pratique, ca veut surtout dire que pas mal de programmeurs utiliseront find(), et s'étonneront de la lenteur de leur code.

    C'est exactement ce qui me fait dire que find() est peut être le plus mauvais exemple qu'on puisse prendre pour dire qu'il faut préférer les algorithmes.

    Francois
    Humm... Je ne suis pas forcément sur...

    Bien avant d'avoir un code rapide, la priorité est au fait d'avoir un code qui fonctionne.

    De ce point de vue, find est l'exemple même de code qui fonctionnera quel que soit le conteneur, et qui permettra de garder quelque chose "qui marche" tant que le conteneur précis dans lequel se trouveront les données ne sera pas fixé

    si, par la suite, il s'avère que, pour une raison ou une autre, nous obtenons de mauvais temps d'exécution, il sera beaucoup plus facile de changer de conteneur (et de fonction de recherche) si on doit rechercher "find(tab.begin(),tab.end() " que si on doit rechercher toutes les boucles que l'on a pu créer dans l'ensemble des fonctions qui seront impactées par le changement de conteneur

    Quelque part, on gagne donc sur les deux tableaux à utiliser find au lieu d'une boucle classique : on obtient directement quelque chose qui fonctionne ET on se donne l'occasion de changer d'avis en cas de besoin
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Réponses: 5
    Dernier message: 20/10/2005, 10h42
  2. [Turbo C++] Fonciton containing for are not expanded inline
    Par BuG dans le forum Autres éditeurs
    Réponses: 6
    Dernier message: 17/02/2003, 06h48
  3. [VB6] For Each ... In ...
    Par Troopers dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 03/02/2003, 12h56
  4. Ce qu'il faut sous la main.
    Par ShinMei dans le forum DirectX
    Réponses: 2
    Dernier message: 18/01/2003, 14h12

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo