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

Langage C++ Discussion :

Au sujet des avantages de la STL


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Invité
    Invité(e)
    Par défaut Au sujet des avantages de la STL
    Cette discussion dérive de structure dedonnée et tableau et démarée suite à l'intervention de davidbrcz
    Citation Envoyé par Davidbrcz Voir le message
    Plus de problème de gestion de la mémoire, enveloppe RAII sur tes données (comprendre que la destruction se fait automatiquement)
    Exemple:
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    #include <iostream>
    #include <string>
    #include <vector>
    #include <limits>
     
    using namespace std;
     
    struct foo{
      string x;
      string y;
    };
     
    int main ()
    {
      short i, a;
     
      cout << "Longueur du tableaux : ";
      cin >> a;
      std::vector<foo> pointer(a); //ici on  réserve un tableau pour a objet, mais on pourrait en ajouter au fur et à mesure.
     
      cin.ignore(numeric_limits<streamsize>::max(), '\n');
     
      for(i = 0 ; i < a ; i++){
        cout << "Entrez une phrase pour tableau 1 array " << i << " : ";
        getline(cin, pointer[i].x);
      }
     
      for(i = 0 ; i < a ; i++){
        cout << "Entrez une phrase pour tableau 2 array " << i << " : ";
        getline(cin, pointer[i].y);
      }
     
      for(i = 0 ; i < a ; i++){
        cout << pointer[i].x << endl;
      }
     
      for(i = 0 ; i < a ; i++){
        cout << pointer[i].y << endl;
      }
      return 0;
    }
    Les vectors, c'est bon, il faut en manger (et la STl en général) car ca offrent plein de possibilité. Ajout d'élement simplifié, accès à la taille de la collection,...

    Recherche sur google et une fois que tu y as gouté, tu ne t'en passes plus.
    =====================================================================================================
    =====================================================================================================
    Citation Envoyé par Davidbrcz Voir le message
    Ajout d'élement simplifié,
    C'est peut être pas la caractéristique que je mettrais en premier, ça...

    Les vector<> c'est bien tant que tu ajoutes des éléments à la fin, mais pour tous les autres cas, c'est pas adapté (il faut des queue ou des lists).

    Pareil pour les suppressions d'ailleurs (la mémoire n'est jamais récupérée, dans un vector, à moins de recourir à des trucs).

    Donc... les vecteurs c'est bien pour allouer des tableaux de taille fixe, déterminée à l'exécution, mais pour les tableaux dont la taille varie, gaffe!

    Francois

  2. #2
    Invité
    Invité(e)
    Par défaut
    Pour moi le fait de connaitre la taille... J'avoue ne pas voir le problème avec les delete[] (le fait d'avoir fait du C avant sans doute...) : quand on ouvre une accolade on la ferme, derrière chaque new, y'a un delete... si on n'y arrive pas, ben, on se met au VB...

    En revanche, en C, on passe son temps à garder la taille de ses tableaux... size(), c'est un sacré bon truc, quand meme...

    Francois

  3. #3
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Pour moi le fait de connaitre la taille... J'avoue ne pas voir le problème avec les delete[] (le fait d'avoir fait du C avant sans doute...) : quand on ouvre une accolade on la ferme, derrière chaque new, y'a un delete... si on n'y arrive pas, ben, on se met au VB...

    En revanche, en C, on passe son temps à garder la taille de ses tableaux... size(), c'est un sacré bon truc, quand meme...

    Francois
    Bah en cas d'exception, disposer d'une enveloppe RAII permet d'éviter les problèmes de gestion de mémoire et d'éviter toutes les fuites.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    En réalité, il y a deux problèmes qu'il s'agit de bien distinguer...

    Le premier sur lequel il faut mettre l'accent est le choix du conteneur proprement dit, mais c'est un problème qui se rencontre aussi en C (avec en plus le fait de *souvent* être tenté de tout recoder à partir de zéro) lorsqu'il s'agit de choisir la "moins mauvaise" structure dynamique pour l'usage que l'on en fait...

    Que ce soit en C ou en C++, l'ajout d'élément ailleurs qu'en début ou en fin de tableau est toujours particulièrement chronophage du fait de la nécessité de réallouer un espace mémoire (même si la fréquence d'apparitions de la réallocation peut être amortie en respectant quelques principes simples, ce qui est le cas de std::vector et qui doit être codé explicitement dans ce but en C) avant de décaler une partie (à déterminer) des éléments d'un nombre (lui aussi à déterminer) de case(s) suffisant pour, enfin, être en mesure d'insérer le(s) élément(s) que l'on veut insérer

    Le gros avantage des tableaux (dynamiques ou non) en C comme en C++ tient surtout au fait de l'accès aux différents élément en temps constant: pour tout tableau contenant N élément et pour autant que 0<=M<N, l'accès à l'indice M se fait en un temps particulièrement intéressant

    Mais il faut bien se rendre compte que, selon l'utilisation que l'on fait des éléments contenus, une pile, une file une liste (simplement ou doublement chainée) ou même un arbre binaire peut s'avérer autrement plus intéressant à manipuler:

    S'il n'est pas question de trier les éléments et que nous sommes dans une logique FIFO ou LIFO, la pile et la file sont particulièrements intéressantes

    Il ne faut, finalement, pas plus de temps pour intervertir deux éléments dans une liste simplement chainée que pour le faire dans un tableau (il "suffit" dans les deux cas de trois opération xor ), modulo le fait qu'il soit peu raisonnable d'envisager une recherche dichotomique des éléments à intervertir.

    Par contre, l'insertion dans une liste se fera en temps constant quelle que soit la position à laquelle elle doit survenir

    Et nous pourrions passer la nuit (enfin, non, pas tout à fait étant donné le peu de structures dynamiques qui existent) à deviser des avantages comparés de chaque structure

    Le deuxième problème tient à que l'on appelle couramment RAII (Ressource Acquisition Is Initialisation) et auquel il faudrait toujours penser à associer son inverse que nous pourrions appeler RRID( Ressource Release Is Destruction) si le terme existait, et, finalement, le respect de la forme canonique orthodoxe de Coplien, du moins quand elle s'applique

    En effet, l'ensemble des classes de la S(T)L assurent une initialisation et une destruction correcte des membres qui les composent, et c'est aussi vrai (bien évidemment) pour les conteneurs

    Mais il faut aussi prendre en compte que, pour les classes copiables et assignables (car certaines classe sont déclarées pour être ni copiables ni assignables comme les flux, par exemple), nous avons l'assurance que la copie et l'assignation ne mèneront pas à des catastrophes dues soit à des fuites mémoire soit à des tentatives de double libération de la mémoire.

    Et il faut avouer que, si le but est d'arriver à une structure dynamique créée "de toute pièces" respectant la forme canonique orthodoxe de coplien, il devient réellement très facile, par distraction, par manque d'habitude ou simplement par manque de sommeil, d'en arriver effectivement à des situations catastrophiques.

    Le but de la S(T)L est de fournir quelque chose de robuste qui nous permet de nous focaliser sur les choses qui sont réellement importantes en rendant transparent pour l'utilisateur tout ce qui a trait à la gestion dynamique de la mémoire.

    Cela ne veut bien sur pas dire qu'un programmeur C++ ne doit absolument pas connaitre le fonctionnement particulier de ce genre de gestion de la mémoire, mais met bel et bien l'accent sur le fait qu'il doit veiller à ne l'utiliser que lorsque c'est réellement nécessaire et indispensable.

    Du moins, pour la règle générale.

    Ensuite, nous sommes effectivement conscients que cette règle générale souffre, comme toute règle, d'exceptions sur des cas bien particuliers.

    Et nous sommes donc bien tous d'accord sur le fait que, de manière exceptionnelle, il peut être intéressant, dans certaines situations, d'abandonner l'usage de la S(T)L au profit de techniques directement issues du C.

    Mais ce genre de décision ne devrait en tout état de cause être prise qu'après avoir clairement optimisé au maximum les algorithmes et s'être assuré que la complexité que cet abandon va impliquer aura bel et bien un effet positif sur les performances.

    J'ai bien conscience que ce que je vais écrire peut avoir de quoi choquer du monde, mais, selon moi, la première qualité d'un code, avant même de faire ce qu'on attend de lui, c'est d'être facilement lisible et compréhensible par la personne qui l'a devant les yeux...

    Or, il n'y a rien à faire, un code qui présente trois instructions distinctes (et "auto commentées") sera en tout état de cause toujours plus simple à comprendre qu'un code obtenant le même résultat en dix instructions distinctes (et tout aussi auto commentées).

    Pour toutes ces raisons et parce que je suis de ceux qui estiment qu'il n'y a pas de mauvaise manière de procéder, mais qu'il y a des manières plus (ou moins) efficace de le faire, je t'avouerai que je trouverai souvent plus efficace de recourir à la STL que de "réinventer la roue"
    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. #5
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Le gros avantage des tableaux (dynamiques ou non) en C comme en C++ tient surtout au fait de l'accès aux différents élément en temps constant: pour tout tableau contenant N élément et pour autant que 0<=M<N, l'accès à l'indice M se fait en un temps particulièrement intéressant
    Note bien que c'est aussi vrai d'une liste, quand on la parcourt dans l'ordre (ou l'ordre inverse si elles sont doublement chaînées). Et ce parcours ordonné est un cas extrèmement courant. En revanche, un tableau aura une représentation plus simple et plus compacte qu'une liste, et une liste sera lente en accès aléatoire.

    C'est un point qui me semble assez curieux, soit dit en passant. La STL fournit des vector<> comme des list<>, mais il me semble que les secondes sont nettement moins utilisées.

  6. #6
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Pour moi le fait de connaitre la taille... J'avoue ne pas voir le problème avec les delete[] (le fait d'avoir fait du C avant sans doute...) : quand on ouvre une accolade on la ferme, derrière chaque new, y'a un delete... si on n'y arrive pas, ben, on se met au VB...

    On pourrait objecter l'Argument de Fénéantise.
    Bizarrement, je préfère écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class Panier
    {
    public:
       Panier(){}
       Panier(int numFruit):panier_(numFruit){}
    private:
       //..
       std::vector<Fruit> panier_;
    };
    à
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
    class Panier
    {
    public:
       Panier():panier_(NULL), numFruit_(0){}
     
       explicit Panier(std::size_t numFruit):
       panier_(new Fruit[numFruit]), 
       numFruit_(numFruit)
       {}
     
       Panier(const Panier& other):
       numFruit_(other.numFruit_), 
       panier(new Fruit[other.numFruit_])
       {
          for(std::size_t i = 0; i < numFruit; ++i)  
             panier_[i] = other.panier_[i];
       }
     
       Panier& operator=(const Panier& other) 
       { 
          if (numFruit_ == other.numFruit_)  
             for (std::size_t i = 0;  i < numFruit_; ++i) 
               panier_[i] = other.panier_[i]; 
          else
          { 
             Panier tmp(other); 
             this->swap(tmp);
          }
          return *this;
       } 
     
       ~Panier() { delete [] panier_; }
     
       void swap( Panier& other) 
       {
          std::swap(numFruit_, other.numFruit_);  
          std::swap(panier_, other.panier_); 
       }
     
    private:
       //...
       Fruit* panier_;
       std::size_t numFruit;
     };

  7. #7
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Pour continuer l'argument de arzar je dirais que justement si tu veux faire des delete etc, en gros géré la mémoire alors autant faire du C. En C++ on a tous ce qui faut pour encapsuler ces comportements et éviter de courir à la catastrophe (ou pas d'ailleurs, après tout avec de la rigueur ça passe.) alors pourquoi s'en priver?
    On peut rajouter l'exemple de la désallocation dans le cas d'une exception qui même simple t'obliges à gérer deux fois la libération de la donnée.. (que ça soit un lock, de la mémoire, un fichier etc).

  8. #8
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Goten Voir le message
    Pour continuer l'argument de arzar je dirais que justement si tu veux faire des delete etc, en gros géré la mémoire alors autant faire du C. En C++ on a tous ce qui faut pour encapsuler ces comportements et éviter de courir à la catastrophe (ou pas d'ailleurs, après tout avec de la rigueur ça passe.) alors pourquoi s'en priver?
    On peut rajouter l'exemple de la désallocation dans le cas d'une exception qui même simple t'obliges à gérer deux fois la libération de la donnée.. (que ça soit un lock, de la mémoire, un fichier etc).
    Je suis, de manière générale, d'accord avec toi, mais il me semble nécessaire d'apporter une certaine nuance...

    Effectivement, dans 90 à 95 % des cas, il serait dommage de se priver des facilités apportées par le langage.

    Mais dans les 5 à 10 % des cas restant, il peut effectivement arriver que la S(T)L ne soit pas satisfaisante et que, pour des raisons propres au projet, ou à une partie du projet, on puisse décider de s'en passer, tout en ne voulant pas forcément se tourner vers un langage "de plus bas niveau"...

    En effet, C++ tient cette position particulière qui consiste à être le langage "haut niveau" permettant le plus une gestion "bas niveau" (à moins que ce soit la position d'être le langage "bas niveau" permettant le plus une gestion "haut niveau" )

    Je trouverais (à titre personnel) aberrant de décider de se passer de l'ensemble parce que, sur un code de 1000 instructions, nous nous trouvons confronté à 100 ou 200 instructions qui justifient des optimisations impossibles à apporter avec la S(T)L

    (évidemment, les valeurs citées le sont à titre indicatif et peuvent être multipliées à l'envie )
    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

  9. #9
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Goten Voir le message
    Pour continuer l'argument de arzar je dirais que justement si tu veux faire des delete etc, en gros géré la mémoire alors autant faire du C.
    Ouais, si j'étais tordu, je te dirais bien que si tu ne veux pas gérer la mémoire, pourquoi ne pas faire du Java ou du C#.... Et si les pointeurs t'effraient, le VB, peut être?

    Sérieusement, tu peux vouloir faire du C++ (ou ajouter du C++ à ton C) pour plein de raisons,

    1- parce que tu peux utiliser la STL pour toutes les petites structures qui n'ont pas besoin d'aller vite
    2- parce que la STL c'est des algorithmes tous prets
    3- parce que les iostream
    4- parce que les classes et un controle de types un peu plus sérieux
    5- parce que les templates c'est mieux que les macros
    6- parce que la librairie graphique que tu utilises l'impose
    7- parce que ton compilateur te le permet...

    Sans pour autant devoir absolument abandonner tes pointeurs, et la possibilité de faire des delete dès que tu n'as plus besoin de la mémoire, ni avoir à te méfier du fait que la STL initialise tout ce qu'elle touche. Si tu traites de gros volumes, c'est en général crucial.

    Citation Envoyé par Goten Voir le message
    En C++ on a tous ce qui faut pour encapsuler ces comportements et éviter de courir à la catastrophe (ou pas d'ailleurs, après tout avec de la rigueur ça passe.) alors pourquoi s'en priver?
    Mais c'est quoi cette catastrophe annoncée? Je veux dire, quelqu'un qui ne sait pas ce qu'est un pointeur, ou qui n'est pas capable de faire un new sans se planter, il faut qu'il fasse plombier, pas informaticien (ou alors du VB...).

    Perso, les erreurs de mémoire sont généralement les trucs les plus faciles à débuguer, y'a plein d'outils pour ca. Les vrais bugs, il ne sont pas là.

    Par ailleurs, il ne s'agit pas de se priver d'utiliser les vector<> (comme tout le monde, mon code en est truffé), juste d'en finir avec l'idée que les new, les delete ou les pointeurs rendent sourd... (ou font pousser les poils du nez)

    Citation Envoyé par Goten Voir le message
    On peut rajouter l'exemple de la désallocation dans le cas d'une exception qui même simple t'obliges à gérer deux fois la libération de la donnée.. (que ça soit un lock, de la mémoire, un fichier etc).
    Oui, mais dans le cas de tableaux de types natifs (99% de mes new) ceci n'arrive à peu près jamais... En revanche, les vecteurs ont la mauvaise habitude de s'initialiser et de se copier tout le temps. Si tu veux faire les choses sérieusement, il va aussi falloir écrire du code pour éviter cela. En fait, tu ne gagneras jamais sur tous les tableaux.

    Ce que je veux dire, c'est que se priver des new et des delete parce que "c'est dangereux" n'est pas raisonnable. D'abord, ce n'est pas vraiment dangereux: si tu codes mal, les vector ne te sauveront pas de la catastrophe. Et si tu ne débugues pas ton code, de toutes façons les utilisateurs auront tes bugs (vector ou pas). Ensuite, parce que dans un grand nombre de cas (genre t'as besoin d'un gros tableau d'entiers ou de POD dont tu connais la taille à l'exécution, pour un calcul, et tu veux le libérer à la fin du calcul) il n'y en a pas, de danger.

    Une fois de plus, presque tous les défenseurs des new et des delete utilisent les vector, et la STL, je ne comprends pas pourquoi il faudrait se priver d'outils simples, pratiques et de bas niveau...

    Francois

  10. #10
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Ouais, si j'étais tordu, je te dirais bien que si tu ne veux pas gérer la mémoire, pourquoi ne pas faire du Java ou du C#.... Et si les pointeurs t'effraient, le VB, peut être?
    Rooh de suite les mots qui fâche. (36 éme degrés ). Encore une fois on parle pas de ne pas gérer la mémoire, mais de la gérer d'une autre manière et plus haut niveau.
    Bon et aussi pour casser une autre idée, non les pointeurs ne m'effraient pas. Quand j'ai commencé le C++ (oui j'ai commencé directement sans la case C) alors oui j'évitais les pointeurs comme la peste, depuis j'ai appris à m'en servir. De plus entre temps je me suis mis au C (pour l'os dev notamment) et donc j'ai vraiment du me mettre à la gestion de la mémoire et des pointeurs. Donc non maintenant un code qui contient des pointeurs ne me dérange pas outre mesure quand à sa compréhension et à son utilisation.
    De plus oui les pointeurs sont bénéfiques mais maintenant j'ai tendance à les utiliser encapsulé dans des structures de plus haut niveau qui véhicule plus de sens et gèrent correctement leur durée de vie. J'aime bien citer ce que dis Scott meyers à ses étudiants à ce sujet d'ailleurs :

    "- POINTERS ARE YOUR ENEMIES, because they lead to the kinds of problems that auto_ptr is designed to eliminate.

    Puis:

    "- POINTERS ARE YOUR FRIENDS, because operations on pointers can't throw.

    "Then I tell them to have a nice day :-)
    Et Sutter d'expliciter [1] :
    - USE POINTERS BECAUSE THEY ARE YOUR FRIENDS, because operations on pointers can't throw.

    - KEEP THEM FRIENDLY BY WRAPPING THEM IN MANAGER OBJECTS like auto_ptrs, because this guarantees cleanup. This doesn't compromise the nonthrowing advantages of pointers because auto_ptr operations never throw either (and you can always get at the real pointer inside an auto_ptr whenever you need to).
    Je trouve que ça résume bien l'idée que j'ai en tête quand je programme avec des pointeurs. A noter que quand même tant que je peux et que j'y suis pas forcé je passe par référence (ou par copie dans certains cas).

    Citation Envoyé par fcharton Voir le message
    Mais c'est quoi cette catastrophe annoncée? Je veux dire, quelqu'un qui ne sait pas ce qu'est un pointeur, ou qui n'est pas capable de faire un new sans se planter, il faut qu'il fasse plombier, pas informaticien (ou alors du VB...).


    Perso, les erreurs de mémoire sont généralement les trucs les plus faciles à débuguer, y'a plein d'outils pour ca. Les vrais bugs, il ne sont pas là.
    Hum je suis pas d'accord, un segfault donnant lieu à un UB c'est pas des faciles à débogué car justement ça peut ne pas arriver. Et si on soit la loi de murphy y'a toute les chances pour que ça arrive lors d'une présentation. En effet un new sans se planter c'est pas surhumain mais dans un programme qui devient conséquent tu t'exposes à d'autres risques (double delete etc) mais qui restent eux aussi gérable.

    Enfin je te ferais remarquer que j'ai nuancé en disant catastrophe ... ou non. Ce qui montre bien que je réfute pas du tout ce que tu dis, je dis juste qu'il y'a d'autres maniéres de faire.


    Citation Envoyé par fcharton Voir le message
    Une fois de plus, presque tous les défenseurs des new et des delete utilisent les vector, et la STL...
    Au vue de ce qui est enseigner et des codes qu'on peut voir ici, tu n'as pas tout a fait raison...



    [1]: http://www.gotw.ca/gotw/059.htm

  11. #11
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Bizarrement, je préfère écrire :
    Oui oui, moi aussi, mais je reste persuadé que


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int *tab=new int[taille];
    for(int i=0;i<taille;i++) tab[i]=i;
    f(tab);
    delete[] tab;
    est plus propre, que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    std::vector<int> tab(taille); 
    // allez une initialisation inutile... 
    std::iota(tab.begin(),tab.end()); 
    // je t'épargne le code avec generate, plus crade encore
    f(&tab[0]);
    // ben oui, la fonction f, système ou librairie externe, elle veut un pointeur
    /* et pis là, t'as intérêt à ne pas avoir besoin de la mémoire, 
        parce que tab reste alloué, ou alors faut aimer un code 
       de 100 000 lignes, coupé en 10 000 fonctions de 10 lignes... */
    Sérieusement, l'argument de fainéantise ne veut pas dire grand chose ici. Pour les map, les list, pas de pb, pour les vectors, bah !

    Francois

  12. #12
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Oui oui, moi aussi, mais je reste persuadé que


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int *tab=new int[taille];
    for(int i=0;i<taille;i++) tab[i]=i;
    f(tab);
    delete[] tab;
    est plus propre, que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    std::vector<int> tab(taille); 
    // allez une initialisation inutile... 
    std::iota(tab.begin(),tab.end()); 
    // je t'épargne le code avec generate, plus crade encore
    f(&tab[0]);
    // ben oui, la fonction f, système ou librairie externe, elle veut un pointeur
    /* et pis là, t'as intérêt à ne pas avoir besoin de la mémoire, 
        parce que tab reste alloué, ou alors faut aimer un code 
       de 100 000 lignes, coupé en 10 000 fonctions de 10 lignes... */
    Sérieusement, l'argument de fainéantise ne veut pas dire grand chose ici. Pour les map, les list, pas de pb, pour les vectors, bah !

    Francois
    Pas d'accord, dans ce cas, tu encapsules ton tableau dans un boost::scoped_array ou un shared_array à la limite. Là, on n'est pas très exception safe

  13. #13
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    std::vector<int> tab(taille); 
    // allez une initialisation inutile...
    Question : Es-tu tombé sur des cas où une telle initialisation avait un véritable impact sur le programme ? Je demande ça, car j'ai lu qu'en D, l'initialisation avait lieu par défaut (même sur un int i; ou l'équivalent local d'un int *p = new int[10]), mais qu'on pouvait localement la désactiver. Et j'ai toujours eu l'impression qu'en C++, le fait que int i; ne définisse pas la valeur de i était un résultat d'un mauvais équilibrage entre perf et sécurité.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  14. #14
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Question : Es-tu tombé sur des cas où une telle initialisation avait un véritable impact sur le programme ?
    Avec des int, seulement sur de très gros tableaux, ou quand on a un grand nombre de vecteurs (par exemple une structure arborescente représentée par des "vector de vector". L'exemple typique serait une arborescence dont on te donne d'abord la structure et ensuite les données. Si tu veux préparer tes vectors (avec des resize), tu vas tout initialiser.

    Tu pourrais faire des reserve(), mais alors il te faut garder les informations de taille, et tu devras absolument faire des push_back() pour remplir tes vecteurs (c'est à dire les remplir dans l'ordre croissant de leurs indices). Par ailleurs, le push_back() génère un peu de copie, je crois... Tu peux aussi redéfinir ton conteneur pour éviter l'initialisation (si je me souviens bien, Koenig et Moo ont une jolie discussion à ce sujet), mais bon, tout ca pour ca!

    Avec des types un tout petit peu plus complexes (struct composites, ou juste string) ca devient très visible très vite.

    Je suis certain que tu peux eviter la plupart des initialisations et des copies inutiles, mais cela demande du travail. On est loin de la simplicité enfantine que l'on prête aux vectors...

    Personnellement j'ai deux cas précis en tête: l'un portant sur des données simples mais arborescentes (donc beaucoup de vecteurs), l'autre sur un unique vecteur, mais assez gros. Dans les 2 cas, on parle d'un bon 15% au chargement, pas spectaculaire, mais visible pour l'utilisateur.

    Je ne suis pas absolument certain qu'il ne s'agit que de l'initialisation, mais dans les deux programmes, récrire les structures de données de grande taille, faites en vector<> lors du prototypage, en utilisant des pointeurs classiques une fois que le proto était testé et les algos maitrisés, s'est traduit pas un gain important de vitesse (entre 25 et 35%...). De façon intéressante, ce constat n'est pas vrai pour les algorithmes de la STL, juste les conteneurs...

    Citation Envoyé par JolyLoic Voir le message
    Je demande ça, car j'ai lu qu'en D, l'initialisation avait lieu par défaut (même sur un int i; ou l'équivalent local d'un int *p = new int[10]), mais qu'on pouvait localement la désactiver. Et j'ai toujours eu l'impression qu'en C++, le fait que int i; ne définisse pas la valeur de i était un résultat d'un mauvais équilibrage entre perf et sécurité.
    Je suis un peu d'accord en fait. Je crois qu'à l'origine, le C++ a été voulu comme un langage capable d'etre aussi portable et bas niveau que le C. Dans ce contexte, l'absence d'initialisation par défaut est une bonne idée (il y a des environnements dans lesquels ce serait pénalisant). Maintenant, et compte tenu de l'évolution du C++ vers un langage compilé de haut niveau, essentiellement destiné à l'informatique classique, on est en droit de se poser la question.

    Francois

Discussions similaires

  1. [ETUDES] [CNAM] Temoignages au sujet des UE
    Par pinocchio dans le forum Etudes
    Réponses: 40
    Dernier message: 06/02/2009, 22h03
  2. [JAR]au sujet des fichiers jar
    Par bobo_j dans le forum Général Java
    Réponses: 2
    Dernier message: 17/10/2005, 16h54
  3. Au sujet des mots de passe
    Par FranT dans le forum Langage
    Réponses: 6
    Dernier message: 17/09/2002, 22h16
  4. Au sujet des constantes
    Par FranT dans le forum Langage
    Réponses: 8
    Dernier message: 09/08/2002, 11h03

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