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

Téléchargez C++ Discussion :

[À télécharger] [Programmation générique] Classe trait pour le type de passage d'argument


Sujet :

Téléchargez C++

  1. #1
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut [À télécharger] [Programmation générique] Classe trait pour le type de passage d'argument
    Bonjour, Je vous propore un nouvel élément à utiliser : [Programmation générique] Classe trait pour le type de passage d'argument



    Cette fonction permet de choisir automatiquement le meilleur moyen pour le passage d'argument. Elle est tirée de l'article d'Alp Mestan sur les classes de traits et de politiques.



    Qu'en pensez-vous ?

  2. #2
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Juste une question, y a t-il un avantage (d'un point de vue performance) lorsqu'il s'agit d'un int de le passer par copie plutôt que par référence constante ? N'est-ce pas la même taille ?

  3. #3
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par NoIdea Voir le message
    Juste une question, y a t-il un avantage (d'un point de vue performance) lorsqu'il s'agit d'un int de le passer par copie plutôt que par référence constante ? N'est-ce pas la même taille ?
    Les références et les pointeurs ont une taille hardware égale à la taille du mot natif. La taille d'un int est décorélée de la taille de mot native. Donc non, ce n'est pas toujours la même taille (en particulier en 64 bits, ou la taille d'une référence est 64 bits tandis que l'int est resté à 32 bits sur la plupart des plateformes).

    Ceci dit, passer un int en référence constante (ou toute autre donnée dont la taille est égale ou inférieure à celle du mot natif) n'a pas vraiment de sens. En termes de performance, le gain (s'il y a, et j'en doute) est négligeable.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  4. #4
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Si je comprend bien, tu dis que cette classe de politique est uniquement didactique et n'est pas utilisée dans un cas réel ?

  5. #5
    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
    Non, il a juste dit que la taille d'un int n'est pas lié à la taille "natif" du système contrairement à celle d'un pointeur (d'un référence). Et que, pour les int mais aussi pour d'autre type, si la taille est inférieure à celle d'un pointeur le passage par référence ne serait pas nécessairement un gain. Et c'est exactement ce choix que permet de faire cet outil.

    Ne serait-il pas mieux de comparer sizeof(T) avec sizeof(void*) plutôt que 8 ?

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

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Citation Envoyé par NoIdea Voir le message
    Si je comprend bien, tu dis que cette classe de politique est uniquement didactique et n'est pas utilisée dans un cas réel ?

    Bien sur que si, regarde boost::call_traits
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  7. #7
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Non, il a juste dit que la taille d'un int n'est pas lié à la taille "natif" du système contrairement à celle d'un pointeur (d'un référence).
    Il me semblait pourtant que les processeurs 64 bits préféraient les int de taille 64. En tout cas, pour les char, c'est évident.

    Et que, pour les int mais aussi pour d'autre type, si la taille est inférieure à celle d'un pointeur le passage par référence ne serait pas nécessairement un gain.
    Cela je l'avais compris car toute référence est pointeur caché. Cependant, bien que ce ne soit pas "nécessairement un gain", il se peut que cela ne change rien du tout. De plus, même si le pointeur à pour taille 8 octets et le int 4 octets, le gain en performance est négligeable d'après ce que j'ai compris de ceci :

    En termes de performance, le gain (s'il y a, et j'en doute) est négligeable.
    A moins que tu veuilles dire que c'est la référence constante qui n'apporte aucun gain.

    Ne serait-il pas mieux de comparer sizeof(T) avec sizeof(void*) plutôt que 8 ?
    Cela me paraitrait plus cohérent.

    Donc, je redemande, dans le cas de la copie, on peut gagner jusqu'à 7 octets sur les processeurs habituels. Est-ce que cela change quelque chose au performances ?
    Le compilateur n'est-il pas déjà capable d'effectuer ce genre d'optimisation ?
    N'est-ce pas alourdir le temps de compilation pour pas grand chose ?
    Est-ce que la copie permet au compilateur de mieux optimiser (ce qui me semble être la raison qui justifie le plus ce type de politique) ?

    Bien sur, je ne dis pas que cette classe désavantage un programme, je dis juste qu'il me semble qu'elle n'apporte pas de gain majeur. Ais-je tord ?

    Bien sur que si, regarde boost::call_traits
    Je vais regarder voir s'il donne la raison pour laquelle il faut l'utiliser.



    Concernant, toutes ces histoires de copies et de passage par référence, peut-il y avoir un gain en déclarant la variable globale (pas de copie je crois) ? Bien sur, ce serait une optimisation du compilateur pas de moi (et je n'ai aucune idée de comment marche les variables globales).

  8. #8
    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
    ne faudrait-il pas en plus vérifier que le type est copie-constructible et sinon le passer par référence constante?

  9. #9
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par NoIdea Voir le message
    Si je comprend bien, tu dis que cette classe de politique est uniquement didactique et n'est pas utilisée dans un cas réel ?
    Non, elle a une réelle utilité.

    Par exemple, on aurait pu réécrire std::vector<X>::push_back() ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    template <class T>
    class vector
    {
    public:
      // il faudrait ajouter ConstParamType sur le modèle de ParamType
      void push_back(typename Calltraits<T>::ConstParamType value)
      {
        ...
      }
    };
    (pour info, je rappelle que le prototype donnée par C++98 est push_back(T); même pas push_back(T& const)).

    T n'est pas toujours un type de base ; ça peut être absolument n'importe quoi.

    Citation Envoyé par NoIdea Voir le message
    Il me semblait pourtant que les processeurs 64 bits préféraient les int de taille 64. En tout cas, pour les char, c'est évident.
    Plus exactement, ils font ce qu'ils veulent. Mais il y a tellement de code écrit qui définissent "typedef unsigned int uint32" que les vendeurs de compilateurs ont bien souvent décidé de laisser les int sur 32 bits. les long font généralement 64 bits (sur une architecture 64 bits, s'entend).

    Citation Envoyé par NoIdea Voir le message
    Cela je l'avais compris car toute référence est pointeur caché. Cependant, bien que ce ne soit pas "nécessairement un gain", il se peut que cela ne change rien du tout. De plus, même si le pointeur à pour taille 8 octets et le int 4 octets, le gain en performance est négligeable d'après ce que j'ai compris de ceci :
    Il peut y avoir un gain infinitésimal, parce que le microprocesseur est optimisé pour lire des mots de 64 bits (en 64 bits, toujours). Du coup, lire un entier de 32 bits lui demande plus d'opérations microcodées. Ceci-dit, on parle de ce qui se passe dans le microcode, donc d'une fraction de l'horloge externe du microprocesseur. Il y a peu de chance pour que ça ait une répercussion à l'extérieur de celui-ci.

    Citation Envoyé par NoIdea Voir le message
    A moins que tu veuilles dire que c'est la référence constante qui n'apporte aucun gain.
    C'est ce que j'ai dit

    Citation Envoyé par NoIdea Voir le message
    Donc, je redemande, dans le cas de la copie, on peut gagner jusqu'à 7 octets sur les processeurs habituels. Est-ce que cela change quelque chose au performances ?
    Même réponse.

    Citation Envoyé par NoIdea Voir le message
    Le compilateur n'est-il pas déjà capable d'effectuer ce genre d'optimisation ?
    N'est-ce pas alourdir le temps de compilation pour pas grand chose ?
    Non, hélas. Le compilateur a l'obligation de faire ce qu'on lui dit de faire. Il a peu de latitude pour modifier le code (il ne peut le faire que si le code modifié se comporte exactement comme l'original).

    Citation Envoyé par NoIdea Voir le message
    Est-ce que la copie permet au compilateur de mieux optimiser (ce qui me semble être la raison qui justifie le plus ce type de politique) ?
    C'est un débat intéressant : le compilateur peut faire des élisions de code en cas de copie d'objets lourds, notamment s'ils ne sont pas modifiés. Sur le code suivant, un compilateur intelligent n'appellera le constructeur de la classe que s'il lui fait initialiser le paramètre à partir d'une valeur qui n'est pas du type du paramètre :

    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
    template <class T>
    T identify(T t)
    { return t; }
     
    struct X
    {
    ... (beaucoup de données)
      void do() { ... }
    };
     
    int main()
    {
      X x;
      identity(x).do(); // aucune copie, grâce aux 
                          // différentes optimisations du compilateur.
    }
    Le problème est que ce comportement n'est pas défini par le standard (ne pas comprendre que le standard le rend indéfini ; juste qu'il n'en parle pas, et du coup, bien que n'étant pas contraire au standard, il n'est pas obligatoire pour un vendeur de compilateur de l'implémenter).

    Citation Envoyé par NoIdea Voir le message
    Bien sur, je ne dis pas que cette classe désavantage un programme, je dis juste qu'il me semble qu'elle n'apporte pas de gain majeur. Ais-je tord ?
    Oui, parce qu'on parle de tous les types imaginables, pas seulement les types de base.

    Citation Envoyé par NoIdea Voir le message
    Je vais regarder voir s'il donne la raison pour laquelle il faut l'utiliser.
    Ne t'inquiète pas, de telles raisons existent

    Citation Envoyé par NoIdea Voir le message
    Concernant, toutes ces histoires de copies et de passage par référence, peut-il y avoir un gain en déclarant la variable globale (pas de copie je crois) ? Bien sur, ce serait une optimisation du compilateur pas de moi (et je n'ai aucune idée de comment marche les variables globales).
    Si tu souhaites passer par des variables globales, tu te trouves dans un autre problème : n'importe qui peut les modifier et tu sacrifie la réentrance (pas possible d'écrire une fonction récursive, pas possible d'écrire une fonction appelable depuis plusieurs threads,...).
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

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

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Le problème est que ce comportement n'est pas défini par le standard (ne pas comprendre que le standard le rend indéfini ; juste qu'il n'en parle pas, et du coup, bien que n'étant pas contraire au standard, il n'est pas obligatoire pour un vendeur de compilateur de l'implémenter).
    Tu veux rire? La copy-elision est définie par le standard hein!
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  11. #11
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Goten Voir le message
    Tu veux rire? La copy-elision est définie par le standard hein!
    Effectivement. Mea culpa. Et pour référence, parce que j'ai eu du mal à trouver : C++98, 12.8 [class.copy] §15.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  12. #12
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Non, hélas. Le compilateur a l'obligation de faire ce qu'on lui dit de faire. Il a peu de latitude pour modifier le code (il ne peut le faire que si le code modifié se comporte exactement comme l'original).
    Mais ce serait le cas non ?


    Oui, parce qu'on parle de tous les types imaginables, pas seulement les types de base.
    Mais presque tout sizeof(classe ou structure créée par l'utilisateur) > sizeof(void*) ?

    De plus,
    ne faudrait-il pas en plus vérifier que le type est copie-constructible et sinon le passer par référence constante?
    Ne t'inquiète pas, de telles raisons existent
    Je me répète, mais dans le meilleur des cas, sa ne faits gagner que 7 octets ? n'est-ce pas un gain ridicule dans la plupart des cas ?

    Si tu souhaites passer par des variables globales, tu te trouves dans un autre problème : n'importe qui peut les modifier et tu sacrifie la réentrance (pas possible d'écrire une fonction récursive, pas possible d'écrire une fonction appelable depuis plusieurs threads,...).
    Ce n'est pas moi qui le souhaite, ce serait une potentielle optimisation du compilateur. A t-il le droit de faire cela ?


    Dernières questions :

    -Quand ne faut-il pas utiliser cette classe pour le passage par référence par conséquent ?

    -Cette classe peut-elle avoir un impacte significatif sur le temps de compilation si elle est utilisée partout ?

  13. #13
    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
    - Tu pourrais, à l'extrème, l'utiliser à chaque fois, ca t'éviterais d'avoir à réflechir (dans le cas ou un passage par référence peut convenir). Cependant l'interet n'est pas là, l'objectif c'est d'augmenter la généricité du code, si tu codes un conteneur ou un algo générique par exemple, tu ne sais pas nécessairement quel est la taille des types, donc une telle classe pourra avoir un interet dans ce cas.

    - Il faudrait tester, mais étant donné la facon dont est fait la STL, s tu l'utilise uniquement pour augmenter la généricité de ton code, je ne pense pas que ca ralentisse beaucoup plus la compilation que le temps qu'il faut lorsque tu utilises la STL (et si tu utilises ailleurs des outils avec des grosses dose de template alors ca doit être négligeable)

    Pour les cas de copy-elision, le standard définie ce que le compilateur peut faire, mais celui-ci a le choix de le faire ou non. Il est d'ailleurs interessant de regarder les différents choix que l'on peut faire pour implémenter une fonction en tirant profit de ces opérations, le sujet est traité sur C++Next en introduction de la move semantique.

  14. #14
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Tu pourrais, à l'extrème, l'utiliser à chaque fois, ca t'éviterais d'avoir à réflechir (dans le cas ou un passage par référence peut convenir). Cependant l'interet n'est pas là, l'objectif c'est d'augmenter la généricité du code, si tu codes un conteneur ou un algo générique par exemple, tu ne sais pas nécessairement quel est la taille des types, donc une telle classe pourra avoir un interet dans ce cas.
    En effet, cependant, voici tous les problèmes liés à un conteneur utilisant cette classe (au lieu de tout passer par référence constante) :

    -Il faut que le type (on le nomme T) soit copy-constructible.
    -Il faut que sizeof(T) indique réellement la taille allouée pour la copie :
    Supposons que T=Matrix avec Matrix :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Matrix
    {
    float * data;
    //Plein de fonctions.
    };
    La copie de Matrix va faire un new, et pourtant, sizeof(Matrix)<=8.

    -Un gain de performance négligeable.

    Donc, si je somme les avantages :
    -Permet la copie elision.
    Si je somme les désavantages :
    -Peut ne pas marcher.
    -Peut ralentir énormément l'exécution (grosse matrice).


    - Il faudrait tester, mais étant donné la facon dont est fait la STL, s tu l'utilise uniquement pour augmenter la généricité de ton code, je ne pense pas que ca ralentisse beaucoup plus la compilation que le temps qu'il faut lorsque tu utilises la STL (et si tu utilises ailleurs des outils avec des grosses dose de template alors ca doit être négligeable)
    Ok.

  15. #15
    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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Juste un point qui me semble ne pas avoir été cité jusqu'à présent :
    Réaliser une copie peut être plus performant, car le compilateur peut alors savoir qu'il n'y a pas d'aliasing sur la donnée, et donc mieux optimiser.
    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.

Discussions similaires

  1. Réponses: 3
    Dernier message: 22/04/2013, 13h07
  2. Traits pour classes définissant un typedef
    Par Florian Goo dans le forum Langage
    Réponses: 11
    Dernier message: 03/06/2009, 19h09
  3. Types génériques: Class is a raw type
    Par lexsteens dans le forum Débuter avec Java
    Réponses: 2
    Dernier message: 22/03/2008, 05h40
  4. Réponses: 12
    Dernier message: 23/09/2006, 13h12

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