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: Que pensez-vous du mot-clé inline aujourd'hui :

Votants
36. Vous ne pouvez pas participer à ce sondage.
  • c'est toujours d'actualité : je conseille de l'utiliser.

    16 44,44%
  • c'est devenu obsolète : à oublier !

    20 55,56%
Langage C++ Discussion :

Intérêt de "inline" de nos jours : pour ou contre ?


Sujet :

Langage C++

  1. #61
    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
    Serais-je le seul à trouver un illogisme flagrant dans le seul fait d'inliner une fonction exportée d'une dll, ne serait-ce que parce que l'inlining d'un fonction a pour résultat de remplacer l'appel de la dite fonction par le code binaire de son implémentation

    San même prendre en compte les restriction, et bien que ce soient deux points de vues tout à fait orthogonaux, les objectifs de l'un et de l'autre me semblent très clairement incompatibles, pas vous
    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

  2. #62
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Disons que ça n'a vraiment d'intéret que lorsqu'on fait une DLL avec une interface C++: L'implémentation "lourde" de la classe peut être dans la DLL, et les accesseurs peuvent être inlinés...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #63
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 749
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 749
    Points : 10 666
    Points
    10 666
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Serais-je le seul à trouver un illogisme flagrant dans le seul fait d'inliner une fonction exportée d'une dll, ne serait-ce que parce que l'inlining d'un fonction a pour résultat de remplacer l'appel de la dite fonction par le code binaire de son implémentation

    San même prendre en compte les restriction, et bien que ce soient deux points de vues tout à fait orthogonaux, les objectifs de l'un et de l'autre me semblent très clairement incompatibles, pas vous
    Présenté comme ça en effet. Mais il s'agit de fonctions membres de classes qui elles sont exportées.

  4. #64
    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 Aurelien.Regat-Barrel Voir le message
    Présenté comme ça en effet. Mais il s'agit de fonctions membres de classes qui elles sont exportées.
    Je reconnais être parfois buté, mais, pour moi, qu'il s'agisse de fonctions libres ou de fonctions membres ne change pas grand chose...

    Le but premier d'une dll est, pour faire simple, de s'assurer que nous pourrons utiliser une bibliothèque sans tenir compte du compilateur (ou de sa version) ni des options de compilation utilisées pour l'obtenir.

    Si l'on décide de permettre au compilateur de remplacer l'appel d'une fonction par le binaire correspondant à son implémentation, il faut se dire que ce sera le binaire produit par ... le compilateur de l'utilisateur, ce qui nous ramène aux restrictions de cet usage et qui est, finalement, tout à fait incompatible avec le but premier des dll's.

    A ce rythme, autant garder une bibliothèque statique ou, si l'on considère (mais ce n'est jamais qu'une extension due aux capacités propres des dll's) la dll comme le moyen de créer des plugins, autant que les fonctions ne soient pas inlinée, pour justement rester en accord avec le principe même de la dll
    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. #65
    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
    Citation Envoyé par koala01 Voir le message
    Le but premier d'une dll est, pour faire simple, de s'assurer que nous pourrons utiliser une bibliothèque sans tenir compte du compilateur (ou de sa version) ni des options de compilation utilisées pour l'obtenir.
    Déjà, l'indépendance au compilateur d'une DLL n'est valable que si on exporte uniquement des fonctions C, ou sous windows si on fait une DLL COM. C'est assez limité.

    Mais surtout, pour certaines personnes, le but d'une DLL n'est pas ça. Dans une application multi-exécutable, le but d'une DLL peut être de diminuer la taille du code à livrer. Il peut aussi être de permettre la livraison de patchs par mail, même si l'application en elle même est trop grosse pour être livrée ainsi. Il peut enfin être de diminuer les temps de recompilation(*) pour une équipe de dev. Dans ces trois cas, avoir quelques fonctions inlines n'est pas absurde.


    (*) C'est l'argument principal là où je travaille (et la situation prédate mon arrivée, et globalement je la désapprouve).
    Il y a en effet un cas où ça accélère le développement, c'est si on change l'implémentation d'un module sans en changer l'interface, on n'a pas besoin de relinker tous les exécutables qui utilisent ce module pour qu'ils bénéficient de la mise à jour.
    Par contre, si on modifie l'interface, il faut dans les deux cas tout recompiler au final. Mais le développeur qui a modifié l'interface l'a probablement fait dans l'optique d'un exécutable spécifique, et s'il travaille en statique, il n'a à recompiler que cet exécutable là pour tester, la recompilation des autres ayant lieu en asynchrone la nuit, alors que s'il travaille en dynamique, il doit tout recompiler pour effectuer même ses premiers tests.
    Le gain de temps pour le développement de l'utilisation de DLL n'est donc pas forcément évident. Mais de toute façon, je ne pense pas que ce soit le genre de considération qui devrait le plus impacter le choix d'architecture, mais plus les contraintes de déploiement ou de performances, et dans ces deux cas, à part une situation de type plug-in, les DLL ajoutent un niveau de complexité certain.
    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.

  6. #66
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 749
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 749
    Points : 10 666
    Points
    10 666
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Je reconnais être parfois buté, mais, pour moi, qu'il s'agisse de fonctions libres ou de fonctions membres ne change pas grand chose...
    Ce que je veux dire, c'est que la fonction inline est exportée parce qu'elle est membre d'une classe qui l'est. Quand on exporte une classe, on est déjà compiler specific.

    C'est une pratique très courante, il suffit de regarder QObject dans Qt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        QString objectName() const;
        void setObjectName(const QString &name);
     
        inline bool isWidgetType() const { return d_ptr->isWidget; }
     
        inline bool signalsBlocked() const { return d_ptr->blockSig; }
        bool blockSignals(bool b);
    Ils sont très prudents. Ils inlinent pas objectName() ou blockSignals(), mais des getters qui ne changeront à priori jamais. Et ainsi ils arrivent à conserver une très bonne compatibilité binaire. C'est une utilisation réfléchie et modérée de inline.

    Certaines applis ont besoin d'utiliser des DLLs, pour la simple raison que tu ne peux pas vraiment avoir une moitié de tes libs sous forme statique et l'autre sous forme de DLLs. A partir du moment où du code est partagé entre les DLLs "obligatoires" (plugin) et ton exe, ce code doit être partagé sous forme de DLL. Et en général, ce code en commun à toute l'appli est utilisé de manière intensive, donc se pose le problème d'optimiser... et nous y voilà.

    Citation Envoyé par JolyLoic Voir le message
    Mais surtout, pour certaines personnes, le but d'une DLL n'est pas ça. Dans une application multi-exécutable, le but d'une DLL peut être de diminuer la taille du code à livrer. Il peut aussi être de permettre la livraison de patchs par mail, même si l'application en elle même est trop grosse pour être livrée ainsi. Il peut enfin être de diminuer les temps de recompilation(*) pour une équipe de dev. Dans ces trois cas, avoir quelques fonctions inlines n'est pas absurde.
    Je ne suis moi aussi pas convaincu par l'aspect temps de recompilation, dans la mesure où lors du développement ok c'est vrai, mais pour le compilation d'une release finale on s'en fiche un peu vu que c'est pas toutes les 10 minutes qu'on fait ça.

    Il y a aussi d'autres arguments en faveur des DLL, en particulier sur les (très) gros projets. Qt par exemple : la compilation en static de certaines bibliothèques (WebKit) échoue tout simplement si elle n'est pas impossible (Phonon). Cela échoue en général à l'édition des liens :

    I spent some time trying to get QtWebKit to compile on Solaris / UltraSPARC / Sun Studio (CC 5.9), as well as AIX / POWER6 / xlC 7.0. Long story short: it compiles on both, with a large set of patches; it doesn’t link on AIX because the Out-Of-Memory killer kills the linker.
    http://labs.trolltech.com/blogs/2009...ng-convention/

    En ce qui me concerne sous Windows, avec l'option WPO, le linker explose sur WebKit quand le fichier lib qu'il génère commence à dépasser les 2Go...

    Donc sur un projets de plusieurs millions de lignes de code, lier statiquement peut être un véritable problème. Toujours dans cette boîte, ils m'ont dit que rien que pour certaines DLLs ou Exe, le linker montait à 600Mo d'occupation mémoire, sachant qu'il y a 255 DLLs...

    Un autre aspect est l'aspect modularité. Leur logiciel tourne sur 120.000 postes clients... et est configuré sur mesure sur chaque poste... compiler 120.000 versions customisées est impensable, passer par des DLLs est obligatoire. Toutes les grosses applis de ce genre (le client choisit les modules qu'il veut parmi des centaines / milliers disponibles) passent par des DLLs il me semble.

  7. #67
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 749
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 749
    Points : 10 666
    Points
    10 666
    Billets dans le blog
    3
    Par défaut
    En réfléchissant à tout ça, je me pose la question suivante : dans le cas d'un très gros projet découpé en modules qui peuvent être compilés aussi bien sous forme de libs statiques que de dlls, si jamais le projet est trop gros pour être compilé avec une optimisation globale sur l'ensemble du source (WPO), je me demande d'un point de vue performance ce qui sera le plus intéressant :
    - compiler et assembler en même temps toutes les libs sous forme statique mais sans optimisation globale sur l'ensemble du programme
    - compiler séparément chaque module sous forme de DLL mais avec optimisation globale (au niveau de chaque DLL)

    Je pense en particulier à une bibliothèque telle que VTK qui contient dans chaque module des algorithmes très couteux. Il s'agit en gros de savoir ce qui procure la meilleure optimisation :
    - une optimisation poussée spécifique à chaque module (DLL WPO)
    - une optimisation "normale" mais qui couvre l'ensemble des modules (lib statiques)

  8. #68
    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 : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

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

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Citation Envoyé par Aurelien.Regat-Barrel Voir le message
    En réfléchissant à tout ça, je me pose la question suivante : dans le cas d'un très gros projet découpé en modules qui peuvent être compilés aussi bien sous forme de libs statiques que de dlls, si jamais le projet est trop gros pour être compilé avec une optimisation globale sur l'ensemble du source (WPO), je me demande d'un point de vue performance ce qui sera le plus intéressant :
    - compiler et assembler en même temps toutes les libs sous forme statique mais sans optimisation globale sur l'ensemble du programme
    - compiler séparément chaque module sous forme de DLL mais avec optimisation globale (au niveau de chaque DLL)

    Je pense en particulier à une bibliothèque telle que VTK qui contient dans chaque module des algorithmes très couteux. Il s'agit en gros de savoir ce qui procure la meilleure optimisation :
    - une optimisation poussée spécifique à chaque module (DLL WPO)
    - une optimisation "normale" mais qui couvre l'ensemble des modules (lib statiques)
    De toute manière, il ne faut pas reposer sur WPO pour avoir de la perf. Les backends des compilateurs ne sont pas suffisamment performants pour gérer cela. Et même si c'était le cas, ils seront toujours moins performants que le compilateur lui-même. Il est nécessaire de restructurer le code dans ce cas. On a eu le souci, on a modifié la structure, et ça marche. Si le code critique réside dans une unité de compilation, pas la peine d'avoir WPO.

    Après, DLL ou bib statique ? DLL, c'est mieux, moins de risque de perdre des fonctionalités (on est sûr que tous les objets seront initialisés, par exemple un registre initialisé par des objets globaux ne fonctionnera peut-être plus avec une bibliothèque statique.

  9. #69
    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
    Hum je crois que ça part un peu en hors sujet mais je voulais juste ajouter qu'il y a quelques mois j'ai découpé l'executable du jeu sur lequel je travaille chez moi en plusieurs dll liés par un exe pour d'autres raisons que celles citées ici (en plus du temps de link qui effectivement est largement réduit pendant le développement, et ça aide):
    - je voulais que certains modules de l'application exposent des fonctions et classes pour permettre à l'utilisateur d'ajouter du contenu;
    - je voulais que certaines parties soient liés à d'autres dlls de bibliothèques tièrces tout en faisant en sorte que les autres parties soient "indépendantes" - le compilo/linker aidant alors à empecher du code d'une dll censée indépendante à avoir du code appelant les dll tièrces; cela est purement pratique c'est vrai, mais j'essaie de faire en sorte que le compilo/linker m'aide aa maintenir mes besoins sur le projet;

  10. #70
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    j'ai essayé de lire une partie de la discussion car je tente de comprendre ce que fait inline.

    Est-il possible de voir ce qu'il se passe au niveau du code quand on déclare une fonction avec inline?

    J'ai tenté d'utiliser le Disassembly (j'ai VC2010), pour voir ce que cela faisait au niveau du code. D'après ce que j'ai vu, cela ne change rien.

    Par exemple, j'ai une fonction max(a,b) et un autre déclarée inline max2(a,b).

    J'ai posté en bas ce que je vois dans l'assembly, ayant appelé les fonctions dans main comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main(){
    int al=5,bl=0;
     
    int mo=max(al,bl);
     
    mo=max2(al,bl);
    }
    le code des deux fonctions est respectivement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int max(int a,int b){
    return a>b?a:b;
    }
     
    inline int max2(int a,int b){
    return a>b?a:b;
    }

    Au niveau du code assembleur des deux fonctions, c'est aussi pareil (je ne l'ai pas posté).
    Mais peut-être que la différence n'est pas visible au niveau de l'assembly, (ou que qqch n'est pas paramétré dans mon compilateur).

    Merci






    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
    52: int mo=max(al,bl);
    009116BC 8B 45 EC             mov         eax,dword ptr [bl]  
    009116BF 50                   push        eax  
    009116C0 8B 4D F8             mov         ecx,dword ptr [al]  
    009116C3 51                   push        ecx  
    009116C4 E8 5E FA FF FF       call        max (911127h)  
    009116C9 83 C4 08             add         esp,8  
    009116CC 89 45 E0             mov         dword ptr [mo],eax  
    53: 
    54:        o=max2(al,bl);
    009116CF 8B 45 EC             mov         eax,dword ptr [bl]  
    009116D2 50                   push        eax  
    009116D3 8B 4D F8             mov         ecx,dword ptr [al]  
    009116D6 51                   push        ecx  
    009116D7 E8 4C F9 FF FF       call        max2 (911028h)  
    009116DC 83 C4 08             add         esp,8  
    009116DF 89 45 E0             mov         dword ptr [mo],eax

  11. #71
    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
    Pour comprendre réellement ce que fait l'inlining, il faut commencer par s'intéresser au code binaire (allez, nous pouvons nous arrêter au niveau de l'assembleur ) généré.

    Lors d'un appel de fonction "normal", il y a trois étapes principales:
    1. le placement sur la pile des informations de contexte de la fonction appelante (adresse de l'instruction suivante, valeur éventuelle des registres, ...) et "saut" à l'adresse mémoire à laquelle débute la fonction appelée
    2. exécution de la fonction appelée
    3. récupération des informations de contexte de la fonction appelante
    Le mot clé inline a pour objectif de demander au compilateur de remplacer l'appel d'une fonction par le code exécutable de celle-ci.

    Pour faire simple, disons que, cela revient à remplacer l'appel de la fonction appelée par l'étape (2) directement au sein de la fonction appelante.

    Le gain observé est donc de l'ordre du temps nécessaire à effectuer les push de l'étape 1 et les pop de l'étape 3.

    L'avantage ressenti par l'utilisateur sera d'autant plus important à l'exécution que
    1. la fonction appelée est petite
    2. la fonction est appelée souvent
    Cependant, le mot clé inline ne fait que demander au compilateur de procéder de la sorte, et il est tout à fait en mesure de choisir s'il le fait ou non en fonction du nombre d'instructions (je parle du nombre d'instructions processeur ) qui sont nécessaires pour effectuer l'ensemble de la fonction appelée.

    Le principe est relativement simple: il appliquera le mot clé inline (s'il est présent) pour toute fonction demandant moins d'un certain nombre d'instructions, et ne l'appliquera plus dés que la fonction en demande d'avantage (il est cependant possible de modifier la limite au niveau des options de compilation).

    Ainsi, un accesseur "simple" comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     type const & Classe::getType() const{return t_;}
    ou une fonction libre peu complexe comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     int max(int i1, int i2){return i1<i2? i2:i1;
    aura beaucoup plus de chance d'être effectivement inlinée qu'une fonction plus complexe

    De plus, une fonction récursive aura très peu de chance d'être effectivement inlinée, même si elle est simple car il est vraiment difficile de déterminer le nombre de récursivités qu'il faudra mettre en oeuvre.

    Il ne sert pas à grand chose d'utiliser la récursivité pour la factorielle, mais la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    inline int factorielle(int i)
    {
        if(i==1)
            return i;
        return i*factorielle(i-1);
    }
    ne sera sans doute pas inlinée, même si elle était codée sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    inline int factorielle(int i)
    {
        return i==1 i : i*factorielle(i-1);
    }
    (en tout cas, tant que l'on ne fait pas en plus entrer la généricité en ligne de compte )
    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

  12. #72
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par koala01 Voir le message
    L'avantage ressenti par l'utilisateur sera d'autant plus important à l'exécution que
    1. la fonction appelée est petite
    2. la fonction est appelée souvent
    Cependant, le mot clé inline ne fait que demander au compilateur de procéder de la sorte, et il est tout à fait en mesure de choisir s'il le fait ou non en fonction du nombre d'instructions (je parle du nombre d'instructions processeur ) qui sont nécessaires pour effectuer l'ensemble de la fonction appelée.
    C'est un peu à cela que sert (en théorie du moins) le mot clef "inline"... Si le compilateur peut facilement juger de la taille du code exécutable d'une fonction, il ne peut connaitre le nombre d'appels à celle ci (il faut pour cela un profileur). Il ne sait généralement pas, non plus (mais je crois que cela change) inliner des fonctions se trouvant dans la boucle intérieure d'un algorithme (souvent la vitesse réelle d'un algorithme dépend de la rapidité de sa boucle intérieure, un appel de fonction, même petite, à l'intérieur peut faire une grosse différence).

    "inline" est censé être un moyen pour le programmeur de préciser au compilateur qu'une fonction "mériterait" d'être inlinée, bien qu'elle ne soit pas très courte.

    Un autre cas où "inline" est utile, ce sont les templates : une fonction définie dans un entête de classe est automatiquement inlinée, sauf si elle appartient à un template...

    Francois

  13. #73
    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 : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

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

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Un autre cas où "inline" est utile, ce sont les templates : une fonction définie dans un entête de classe est automatiquement inlinée, sauf si elle appartient à un template...
    Elle est aussi inlinée dans le cas des templates (et heureusement !).

  14. #74
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Matthieu Brucher Voir le message
    Elle est aussi inlinée dans le cas des templates (et heureusement !).
    Ce n'est pas ce que disent Josuttis et Vandevoorde (p.72)

    "This may lead to the impression that function template are inline by default. However, they're not. If you write function templates that should be handled as inline functions, you should use the inline specifier (unless the function is inline already because it is defined inside a class definition)."

    http://books.google.com/books?id=Eot...%2B%2B&f=false

    Ce que j'en comprends c'est que les template sont une exception, dans le cas des fonctions (pas inlinées par défaut). Et je crois avoir observé ce comportement dans le cas de fonctions membres de classes template...

    La seule chose garantie, je crois, c'est une fonction template membre d'une classe normale.

    Il est bien sur possible que cela ait évolué depuis la sortie de ce livre (2003). Mais je connais personnellement quelques compilateurs qui, effectivement, n'inlinent pas par défaut tout le code template.

    PS. Pour être précis, voici ce que j'ai retenu...

    1- une fonction template définie dans un .h n'est pas inlinée par défaut (il faut le préciser)
    2- une spécialisation explicite d'une fonction template inlinée par défaut ne l'est pas par défaut (il faut aussi le préciser)
    3- dans le cas d'une classe template : si le code de la fonction se trouve à l'intérieur de la définition de classe (entre les deux {}), il sera inliné (je ne crois pas que ce soit systématique, cependant, le compilateur a probablement son mot à dire dans pas mal d'implémentations), s'il est défini plus loin dans le .h, il ne le sera pas
    4- dans le cas des spécialisations d'une classe template, je ne sais pas, mais j'ai des doutes

    Et même dans le cas où tout ceci est précisément défini dans la norme, j'aurais des doutes quant à l'implémentation sur les différents compilateurs. L'instanciation de templates, c'est notoirement subtil !

    Francois
    Dernière modification par Invité ; 11/03/2010 à 10h19.

  15. #75
    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
    Salut,
    Pour les templates, l'ODR est garanti :
    Citation Envoyé par 3.2. ODR (¤5)
    There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (clause 14), non-static function template (14.5.5), static data
    member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.4) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements.
    Cependant, la norme précise que le seul cas où inline est nécessaire c'est pour les spécialisations explicites :
    Citation Envoyé par 14.7.3 Explicit specialisation ¤14
    An explicit specialization of a function template is inline only if it is explicitly declared to be, and independently
    of whether its function template is.
    En revanche, je veux bien te croire quand tu dis que le comportement peut varier selon le compilo vu que les template ne sont pas forcément le plus facile à gérer.

    @deubelte : l'inlining d'une fonction (au sens où l'appel est remplacé par le code) ne sera visible qu'en release. En général, l'option est désactivé en mode debug.

  16. #76
    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 : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

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

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Le texte est assez clair : une fonction template définie dans une classe est inlinée.
    Je suis d'accord que si elle est déclarée dans la classe et définie à l'extérieur, elle ne sera pas inlinée, puisqu'elle se comporte comme une fonction standard.

    J'ai déjà vu le comportement sur plusieurs compilateurs (Intel et GCC). En mode débug, rien n'est inliné, en mode release, plusieurs fonctions sont inlinées (gain de 10 sur mon code hautement templaté par ex).

  17. #77
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Cependant, la norme précise que le seul cas où inline est nécessaire c'est pour les spécialisations explicites :
    Je ne comprends pas... Ce cas précise la situation des spécialisation explicites d'une fonction template, il ne précise rien sur les autres cas.

    Quid, par exemple des spécialisations explicites de classes... ?

    1- je définis une classe template "de base", une fonction définie à l'intérieur de la définition de classe est inlinée, une en dehors ne l'est pas... (jusque là ca va)
    2- je spécialise (éventuellement partiellement) cette classe, et spécialise donc ses membres (la norme m'y oblige, je crois), je suppose qu'alors le lieu où les fonctions spécialisées sont redéfinies prendra le pas sur la règle précédente pour décider de l'inlining. C'est garanti? C'est dans le standard?
    3- j'ai dans une classe non template une fonction membre template (inlinée car définie dans le header), que je spécialise explicitement, y's'pass' quoi?
    4- même question pour une classe template, ou sa spécialisation...

    Et je pense qu'on peut continuer jusqu'à avoir très mal à la tête...

    En fait, il me semble que le seul cas précis est celui des "fonctions template globales", tout le reste...

    @Matthieu : sur le compilateur que j'utilise (Borland), on dispose d'une série d'options gérant l'inlining. C'est rendu nécessaire par la complexité du débugage, et ca change pas mal de choses à l'exécution. Mais j'ai remarqué qu'un passage avec un profileur montre que, même en "full inline", le compilateur fait parfois des choix...

    Il est très possible qu'il y ait des règles précises (qu'un compilateur suivra ou non), mais je doute qu'elles soient simples...

    Francois
    Dernière modification par Invité ; 11/03/2010 à 11h23.

  18. #78
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par fcharton Voir le message
    2- je spécialise (éventuellement partiellement) cette classe, et spécialise donc ses membres (la norme m'y oblige, je crois), je suppose qu'alors le lieu où les fonctions spécialisées sont redéfinies prendra le pas sur la règle précédente pour décider de l'inlining. C'est garanti? C'est dans le standard?
    Je pense qu'on peut déduire ça étant données les "règles" de base de déduction de quand une fonction est inlinée, effectivement.

    Citation Envoyé par fcharton Voir le message
    3- j'ai dans une classe non template une fonction membre template (inlinée car définie dans le header), que je spécialise explicitement, y's'pass' quoi?
    Cf le post de 3DArchi, il faut préciser toi-même que tu veux qu'elle soit inlinée, car elle est considérée "différente" du modèle qu'elle spéciale au niveau de l'inlining.

    Citation Envoyé par fcharton Voir le message
    4- même question pour une classe template, ou sa spécialisation...
    Là du moment que tu définis ta fonction template à l'intérieur ça devrait être inliné par défaut

  19. #79
    Débutant  
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Points : 217
    Points
    217
    Par défaut
    j'ai étudié moi même les fonctions inline, voila ce qu'il en ressort. Maintenant, j'ai compris ce qu'il se passait. (je fais références avec des couleurs, mais il
    faut pas les prendre en compte).


    Supposons que l’on ait une fonction, l’une déclaré inline l’autre non.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int max(int a,int b){
    return a>b?a:b;
    }
    inline int max2(int a,int b){
    return a>b?a:b;
    }
    La fonction main est alors déclarée comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main(){
       int al=5,bl=0;
       int mo=max(al,bl);
        mo=max2(al,bl);
    }
    Le code mémoire de ces deux fonctions sont :
    -pour max2

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    17: inline int max2(int a,int b){
        18: return a>b?a:b;
        19: }
        20:
    -pour max :

    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
      10: int max(int a,int b){
    00221060 55                   push        ebp  
    00221061 8B EC                mov         ebp,esp  
    00221063 51                   push        ecx  
    00221064 C7 45 FC CC CC CC CC mov         dword ptr [ebp-4],0CCCCCCCCh  
        11: return a>b?a:b;
    0022106B 8B 45 08             mov         eax,dword ptr [a]  
    0022106E 3B 45 0C             cmp         eax,dword ptr [b]  
    00221071 7E 08                jle         max+1Bh (22107Bh)  
    00221073 8B 4D 08             mov         ecx,dword ptr [a]  
    00221076 89 4D FC             mov         dword ptr [ebp-4],ecx  
    00221079 EB 06                jmp         max+21h (221081h)  
    0022107B 8B 55 0C             mov         edx,dword ptr [b]  
    0022107E 89 55 FC             mov         dword ptr [ebp-4],edx  
    00221081 8B 45 FC             mov         eax,dword ptr [ebp-4]  
        12: }
    Le code mémoire de la fonction main est :
    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
     
    50: int al=5,bl=0;
    002211E7 C7 45 FC 05 00 00 00 mov         dword ptr [al],5  
    002211EE C7 45 F8 00 00 00 00 mov         dword ptr [bl],0  
    51:  
    52: int mo=max(al,bl);
    002211F5 8B 45 F8             mov         eax,dword ptr [bl]  
    002211F8 50                   push        eax  
    002211F9 8B 4D FC             mov         edx,dword ptr [al]  
    002211FC 51                   push        ecx  
    002211FD E8 1C FE FF FF       call        max (22101Eh)  
    00221202 83 C4 08             add         esp,8  
    00221205 89 45 F4             mov         dword ptr [mo],eax  
    53: 
    54: mo=max2(al,bl);
    00221208 8B 55 FC             mov         edx,dword ptr [al]  
    0022120B 3B 55 F8             cmp         edx,dword ptr [bl]  
    0022120E 7E 08                jle         main+48h (221218h)  
    00221210 8B 45 FC             mov         eax,dword ptr [al]  
    00221213 89 45 AC             mov         dword ptr [ebp-54h],eax  
    00221216 EB 06                jmp         main+4Eh (22121Eh)  
    00221218 8B 4D F8             mov         ecx,dword ptr [bl]  
    0022121B 89 4D AC             mov         dword ptr [ebp-54h],ecx  
    0022121E 8B 55 AC             mov         edx,dword ptr [ebp-54h]  
    00221221 89 55 F4             mov         dword ptr [mo],edx
    On voit bien l’absence de call, push, à la suite de la fonction max2, alors que ces mots clés existent bien à la suite de la fonction max (cf en rouge). On voit aussi que le code de la fonction max, (qui est identique à celui de max2) se retrouve dans le corps de la fonction main. Ce qui prouve bien que « le code complet de cette fonction est inséré dans le code de l’appelant, c’est le même principe qu’un #define. Cela peut, parmi beaucoup d'autres choses, améliorer les performances, étant donné que l'optimiseur peut intégrer directement le code appelé, voire optimiser le code appelé en fonction du code appelant. » On a donc représenté en vert le code de max2, qui correspond tout a fait au code de max. Cela permet d’éliminer tous les mots cléfs en bleu.

  20. #80
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Attention, la présence du 0xCCCCCCCC montre que c'est encore une compilation en Debug.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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