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

C++ Discussion :

instanciation des templates


Sujet :

C++

  1. #1
    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 instanciation des templates
    http://cpp.developpez.com/cours/cpp/?page=page_14#LXIV

    "Enfin, ce qui est le plus grave, c'est que les instances des template sont en multiples exemplaires dans les fichiers objets générés par le compilateur"


    Si dans un projet on utilise dans 2 fonction un std::vector<int> v; , dans le binaire cette classe sera présente 2 fois ?

  2. #2
    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 guillaume07 Voir le message
    http://cpp.developpez.com/cours/cpp/?page=page_14#LXIV

    "Enfin, ce qui est le plus grave, c'est que les instances des template sont en multiples exemplaires dans les fichiers objets générés par le compilateur"


    Si dans un projet on utilise dans 2 fonction un std::vector<int> v; , dans le binaire cette classe sera présente 2 fois ?
    Le risque est effectivement présent, surtout si tu utilise un std::vector<int> dans deux unités de compilation séparées.
    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

  3. #3
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Hello

    Voilà qui est intéressant. Que se passe-t-il dans le cas où deux unités de compilation s'échangent via des méthodes des std::vector ? Il y a aura deux classes dans le binaire, mais strictement identiques ?
    Find me on github

  4. #4
    screetch
    Invité(e)
    Par défaut
    en general, le code n'est pas dupliqué dans l'executable final. La plupart des linker fusionnent les méthodes dont le code généré est identique.
    ce qui les conduit même parfois a fusionner std::vector<int> et std::vector<float>, et std::vector<A*> et std::vector<B*>
    Dernière modification par screetch ; 04/04/2011 à 15h05.

  5. #5
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Je me disais aussi... ça ferait trop gonfler l'empreinte pour rien.
    Find me on github

  6. #6
    screetch
    Invité(e)
    Par défaut
    bah oui
    ca poserait aussi d'enormes problèmes pour les variables statiques des classes templates; il n'y en aurait pas une pour le programme mais une par module, donc deux modules ne parleraient pas à la même variable... "woups!"

  7. #7
    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
    Citation Envoyé par screetch Voir le message
    ce qui les conduit même parfois a fusionner std::vector<int> et std::vector<float>, et std::vector<A*> et std::vector<B*>


    TU aurais un peu plus de détails ?

  8. #8
    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
    C'est, en réalité, beaucoup plus comlexe que cela...

    Ce dont on est sur tient en plusieurs points:
    1. Le code d'une classe template est, a priori, inliné car le compilateur ne peux créer le code binaire correspondant qu'une fois qu'il sait quel est le type du (des) paramètre(s) template
    2. Le compilateur oublie, d'une unité de compilation à l'autre, ce qu'il a pu faire
    3. Le compilateur reste seul juge de l'opportunité d'inliner (ou non) une fonction déclarée (de manière implicite ou explicite) inline
    4. Si le code d'une fonction (membre d'une classe) template est utilisé, il est très certainement généré au niveau binaire, ce qui ne veut pas dire (tout dépend du compilateur) que l'ensemble des fonctions de la classe template (s'il échoit) le sera d'office
    A partir de là, on peut être tenté de tirer quelques conclusions, qui peuvent parfaitement s'avérer non fondées, telles que:

    • Le code binaire ne sera peut être généré pour l'ensemble d'une classe que pour les instances de celle-ci (par opposition aux références / pointeurs sur les instances de la classe), dans le fichiers où les dites instances sont créées
    • Il n'est pas exclu que l'appelle d'une fonction donnée occasionne l'inlining de celle-ci, et donc sa présence à l'intérieur du binaire, à la place où elle est appelée
    • ...
    Là dessus, il faut aussi prendre l'éventualité de l'instanciation explicite, entre autres pour les types primitifs.

    Il n'est donc pas exclu, malgré tout, que l'ensemble de std::vector<int> se trouve dans libstdxx.a (sous gcc) et que le code ne soit pas forcément inliné chaque fois que l'on a une variable de ce type.

    Et ce n'est qu'un aperçu rapide du problème qu'il peut y avoir à donner une réponse par trop affirmative
    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
    screetch
    Invité(e)
    Par défaut
    Si le code généré est abolument identique pourquoi en avoir plusieurs versions (une copie en quelques sortes?)
    Certains linker fusionnent donc les methodes qui ont exactement le meme code assembleur généré.
    vector<int> et vector<float> pourraient en faire partie, par exemple. A part gérer des données de 32 bits de long, y'a pas de code spécialisé.

  10. #10
    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
    Citation Envoyé par screetch Voir le message
    Si le code généré est abolument identique pourquoi en avoir plusieurs versions (une copie en quelques sortes?)
    Certains linker fusionnent donc les methodes qui ont exactement le meme code assembleur généré.
    vector<int> et vector<float> pourraient en faire partie, par exemple. A part gérer des données de 32 bits de long, y'a pas de code spécialisé.
    oui effectivement thxs

  11. #11
    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 screetch Voir le message
    Si le code généré est abolument identique pourquoi en avoir plusieurs versions (une copie en quelques sortes?)
    Certains linker fusionnent donc les methodes qui ont exactement le meme code assembleur généré.
    vector<int> et vector<float> pourraient en faire partie, par exemple. A part gérer des données de 32 bits de long, y'a pas de code spécialisé.
    Ce dont tu parles c'est du LTO (link time optimization), clang le fait en O4 (mais il faut le gold linker) et gcc le fait depuis la version 4.5 (4.6 ?)
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  12. #12
    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
    Il y a quand même des contraintes où le compilateur est obligé de fusionner des morceaux de deux vector<T> (pour un même T) :
    - Pour les variables statiques
    - Quand on prend l'adresse d'une fonction

    A partir de là, il ne me semble pas idiot que comme le mécanisme de fusion existe, il serve dans d'autres cas où il est approprié...

    Par contre, la fusion entre un vector<T> et un vector<U>, même quand le code est identique, est un autre concept, lié uniquement à l'optimisation et non pas à la correction du programme. On peut manuellement forcer un peu cette optimisation (par exemple faire dériver par spécialisation tous les vector<T*> d'un vector<void*> qui contient la quasi totalité du code).
    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.

  13. #13
    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
    De plus, la LTO ne peut, à mon sens, s'appliquer que... si le code n'a pas été effectivement inliné.

    En effet, le principe de l'inlining est de remplacer, purement et simplement, l'appel de la fonction par le code de la fonction appelée, alors qu'autrement, il "suffit" au compilateur de fournir un symbole de la fonction appelée.

    Dans le premier cas, il devient virtuellement impossible au linker (ou à tout autre système passant après le compilateur) de distinguer ce qui fait partie d'une fonction appelée de la fonction appelante.

    Dans le second cas, le linker a effectivement l'occasion de reconnaitre les différents symboles et, le fait que l'appel d'une même fonction sera représenté (a priori du moins) par un même symbole (y compris si le type est un typedef) devrait, effectivement, permettre de fusionner vector<T> et vector<U> si T et U ne sont, par exemple, que des typedef différents d'un même type (on peut donc, par conséquent, effectivement envisager que vector<T*> soit fusionné avec l'instanciation du vector utilisant le type utilisé par le typedef de uintptr_t, par exemple).
    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

  14. #14
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    On peut manuellement forcer un peu cette optimisation (par exemple faire dériver par spécialisation tous les vector<T*> d'un vector<void*> qui contient la quasi totalité du code).
    c'est meme préconisé avec mesure a la clé par stroustrup dans son papier a OOPSLA 09 :

    http://www.open-std.org/jtc1/sc22/wg...2009/n2911.pdf

  15. #15
    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
    Citation Envoyé par screetch Voir le message
    Si le code généré est abolument identique pourquoi en avoir plusieurs versions (une copie en quelques sortes?)
    Certains linker fusionnent donc les methodes qui ont exactement le meme code assembleur généré.
    vector<int> et vector<float> pourraient en faire partie, par exemple. A part gérer des données de 32 bits de long, y'a pas de code spécialisé.
    encore un doute... les fonctions type push_back générés ne prennent pas en paramètre soit un int soit un float selon qu'il s'agisse d'un vector<int> ou d'un vector<float> auquel cas, les codes ne sont pas identiques ?

  16. #16
    screetch
    Invité(e)
    Par défaut
    ca depend de la convention d'appel, je ne suis pas sur la.

Discussions similaires

  1. Utilisation des templates
    Par vanitom dans le forum MFC
    Réponses: 21
    Dernier message: 01/08/2007, 11h07
  2. Réponses: 1
    Dernier message: 18/04/2006, 12h24
  3. [XSL]portée des templates??
    Par luta dans le forum XSL/XSLT/XPATH
    Réponses: 5
    Dernier message: 23/02/2006, 10h53
  4. [XSL] utilisation des templates
    Par KibitO dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 16/12/2005, 15h54
  5. Utilisation des templates
    Par mikky dans le forum C++
    Réponses: 1
    Dernier message: 14/09/2005, 12h59

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