Question Quand dois-je écrire le mot-clé 'inline' pour une fonction / méthode?


Quand devrais-je écrire le mot clé inline pour une fonction / méthode en C ++?

Après avoir vu quelques réponses, quelques questions connexes:

  • Quand devrais-je ne pas écrire le mot-clé 'inline' pour une fonction / méthode en C ++?

  • Quand le compilateur ne saura-t-il pas quand faire une fonction / méthode 'inline'?

  • Est-ce important si une demande est multithread quand on écrit 'inline' pour une fonction / méthode?


424
2017-11-18 21:46


origine


Réponses:


Oh mec, une de mes bêtes noires.

inline est plus comme static ou extern qu'une directive indiquant au compilateur d'intégrer vos fonctions. extern, static, inline sont des directives de liaison, utilisées presque exclusivement par l'éditeur de liens, pas par le compilateur.

Il est dit que inline indications au compilateur que vous pensez que la fonction devrait être inline. Cela a peut-être été vrai en 1998, mais une décennie plus tard le compilateur n'a pas besoin de tels conseils. Sans compter que les humains ont généralement tort quand il s’agit d’optimiser le code, la plupart des compilateurs ignorent l’indice.

  • static - le nom de variable / fonction ne peut pas être utilisé dans d'autres unités de traduction. Linker doit s'assurer qu'il n'utilise pas accidentellement une variable / fonction définie statiquement d'une autre unité de traduction.

  • extern - utiliser ce nom de variable / fonction dans cette unité de traduction mais ne pas se plaindre s'il n'est pas défini. L'éditeur de liens le triera et s'assurera que tout le code qui a essayé d'utiliser un symbole externe a son adresse.

  • inline - cette fonction sera définie en plusieurs unités de traduction, ne vous inquiétez pas. L'éditeur de liens doit s'assurer que toutes les unités de traduction utilisent une seule instance de la variable / fonction.

Remarque: Généralement, déclarer des modèles inline est inutile, car ils ont la sémantique de liaison de inline déjà. cependant, explicit spécialisation et instanciation de modèles exiger inline à utiliser.


Réponses spécifiques à vos questions:

  • Quand dois-je écrire le mot-clé 'inline' pour une fonction / méthode en C ++?

    Seulement lorsque vous souhaitez que la fonction soit définie dans un en-tête. Plus précisément seulement lorsque la définition de la fonction peut apparaître dans plusieurs unités de traduction. C'est une bonne idée de définir de petites fonctions (comme dans une ligne) dans le fichier d'en-tête, car cela donne au compilateur plus d'informations avec lesquelles travailler tout en optimisant votre code. Cela augmente également le temps de compilation.

  • Quand ne devrais-je pas écrire le mot-clé 'inline' pour une fonction / méthode en C ++?

    N'ajoutez pas en ligne juste parce que vous pensez que votre code s'exécutera plus vite si le compilateur l'insère.

  • Quand le compilateur ne saura-t-il pas quand faire une fonction / méthode 'inline'?

    Généralement, le compilateur sera capable de faire cela mieux que vous. Cependant, le compilateur n'a pas l'option de code en ligne s'il n'a pas la définition de la fonction. Dans le code optimalement optimisé généralement tous private les méthodes sont intégrées si vous le demandez ou non.

    En réserve pour empêcher l’incrustation dans GCC, utilisez __attribute__(( noinline )), et dans Visual Studio, utilisez __declspec(noinline).

  • Est-ce important si une application est multithread quand on écrit 'inline' pour une fonction / méthode?

    Le multithreading n'affecte en rien l'inline.


679
2017-11-18 22:22



Vous devez toujours incorporer explicitement votre fonction lorsque vous faites une spécialisation de modèle (si la spécialisation se trouve dans le fichier .h)


26
2017-11-18 22:02



Je voudrais contribuer à toutes les grandes réponses dans ce fil avec un exemple convaincant pour disperser tout malentendu restant.

Étant donné deux fichiers sources, tels que:

  • inline111.cpp:

    #include <iostream>
    
    void bar();
    
    inline int fun() {
      return 111;
    }
    
    int main() {
      std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun;
      bar();
    }
    
  • inline222.cpp:

    #include <iostream>
    
    inline int fun() {
      return 222;
    }
    
    void bar() {
      std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun;
    }
    

  • Cas A:

    Compiler:

    g++ -std=c++11 inline111.cpp inline222.cpp
    

    Sortie:

    inline111: fun() = 111, &fun = 0x4029a0
    inline222: fun() = 111, &fun = 0x4029a0
    

    Discussion:

    1. Même toi tu devrais avoir des définitions identiques de ton inline fonctions, le compilateur C ++ ne le marque pas si ce n'est pas le cas (en fait, en raison de compilation séparée il n'a aucun moyen de le vérifier). C'est votre devoir de faire cela!

    2. Linker ne se plaint pas de Une règle de définition, comme fun() est déclaré comme inline. Cependant, parce que inline111.cpp est la première unité de traduction (qui appelle fun()) traité par le compilateur, le compilateur instancié fun() sur son premier appel-rencontre dans inline111.cpp. Si le compilateur décide ne pas étendre fun() sur son appel de n'importe où ailleurs dans votre programme (par exemple. de inline222.cpp), l'appel à fun() sera toujours lié à son instance produite à partir de inline111.cpp (l'appel à fun() à l'intérieur inline222.cpp peut également produire une instance dans cette unité de traduction, mais elle restera non liée). En effet, cela est évident à partir de l'identique &fun = 0x4029a0 impressions

    3. Enfin, malgré la inline suggestion au compilateur de élargir en fait le one-liner fun(), il ne tient pas compte votre suggestion complètement, ce qui est clair parce que fun() = 111 dans les deux lignes.


  • Cas B:

    Compiler  (avis ordre inverse):

    g++ -std=c++11 inline222.cpp inline111.cpp
    

    Sortie:

    inline111: fun() = 222, &fun = 0x402980
    inline222: fun() = 222, &fun = 0x402980
    

    Discussion:

    1. Cette affaire affirme ce qui a été discuté dans Cas A.

    2. Notez un point important, que si vous commentez l'appel réel à fun() dans inline222.cpp (par exemple. commenter cout-déclaration inline222.cpp complètement) alors, malgré l'ordre de compilation de vos unités de traduction, fun() sera instancié sur sa première rencontre d'appel dans inline111.cpp, ce qui entraîne l'impression pour Cas B comme inline111: fun() = 111, &fun = 0x402980.


  • Cas C:

    Compiler  (avis -O2):

    g++ -std=c++11 -O2 inline222.cpp inline111.cpp
    

    ou

    g++ -std=c++11 -O2 inline111.cpp inline222.cpp
    

    Sortie:

    inline111: fun() = 111, &fun = 0x402900
    inline222: fun() = 222, &fun = 0x402900
    

    Discussion:

    1. Comme si décrit ici, -O2 l'optimisation encourage le compilateur à élargir en fait les fonctions qui peuvent être intégrées (Notez aussi que -fno-inline est défaut sans options d'optimisation). Comme il ressort de l’impact ici, le fun() a été effectivement en ligne élargi (selon sa définition dans ce particulier unité de traduction), résultant en deux différent  fun() impressions Malgré cela, il y a encore seulement un instance globalement liée de fun() (comme requis par la norme), comme il est évident de identique  &fun imprimer.

24
2017-08-16 09:45



1) De nos jours, à peu près jamais. Si c'est une bonne idée d'intégrer une fonction, le compilateur le fera sans votre aide.

2) toujours Voir # 1.

(Edité pour refléter que vous avez cassé votre question en deux questions ...)


17
2017-11-18 21:47



Quand ne devrais-je pas écrire le mot-clé 'inline' pour une fonction / méthode en C ++?

Si la fonction est définie dans le .cpp fichier, vous devriez ne pas écrivez le mot clé

Quand le compilateur ne saura-t-il pas quand faire une fonction / méthode 'en ligne'?

Il n'y a pas une telle situation. Le compilateur ne peut pas faire une fonction en ligne. Tout ce qu'il peut faire est d'inclure certains ou tous les appels à la fonction. Il ne peut pas le faire s'il n'a pas le code de la fonction (dans ce cas, l'éditeur de liens doit le faire s'il est capable de le faire).

Est-ce important si une application est multithread quand on écrit 'inline' pour une fonction / méthode?

Non, ça n'a pas d'importance du tout.


8
2018-01-16 20:46



En réalité, à peu près jamais. Tout ce que vous faites est de suggérer que le compilateur insère une fonction donnée (par exemple, remplace tous les appels à cette fonction / w son corps). Bien sûr, il n'y a aucune garantie: le compilateur peut ignorer la directive.

Le compilateur fera généralement un bon travail de détection et d’optimisation.


4
2017-11-18 21:48



  • Quand le compilateur ne saura-t-il pas quand faire une fonction / méthode 'en ligne'?

Cela dépend du compilateur utilisé. Ne croyez pas aveuglément qu'aujourd'hui, les compilateurs savent mieux que les humains comment s'y intégrer et que vous ne devriez jamais l'utiliser pour des raisons de performances, car c'est une directive de liaison plutôt qu'un conseil d'optimisation. Bien que je convienne qu'idéologiquement ces arguments sont justes, rencontrer la réalité pourrait être une chose différente.

Après avoir lu plusieurs discussions autour de moi, j'ai essayé par curiosité les effets de l'inline sur le code que je travaillais et les résultats ont été que j'ai eu un accélération mesurable pour GCC et aucune accélération pour le compilateur Intel.

(Plus de détails: simulations mathématiques avec peu de fonctions critiques définies en dehors de la classe, GCC 4.6.3 (g ++ -O3), ICC 13.1.0 (icpc -O3); ajout en ligne aux points critiques accélérés de + 6% avec le code GCC).

Donc, si vous qualifiez GCC 4.6 en tant que compilateur moderne, le résultat est que la directive inline est toujours importante si vous écrivez des tâches exigeantes en CPU et que vous savez exactement quel est le goulot d'étranglement.


4
2018-03-16 01:06



gcc par défaut n'inline aucune fonction lors de la compilation sans   optimisation activée. Je ne sais pas à propos de visual studio - deft_code

Je l'ai vérifié pour Visual Studio 9 (15.00.30729.01) en compilant avec / FAcs et en regardant le code de l'assembly: Le compilateur a produit des appels aux fonctions membres sans optimisation activée dans déboguer mode. Même si la fonction est marquée avec __forceinline, aucun code d'exécution en ligne n'est produit.


2
2017-07-17 02:08



Vous voulez le mettre au tout début, avant le type de retour. Mais la plupart des compilateurs l'ignorent. Si c'est défini, et qu'il a un plus petit bloc de code, la plupart des compilateurs le considèrent en ligne quand même.


0
2017-11-18 21:50