web-dev-qa-db-fra.com

Quand devrais-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 pas écrire le mot clé 'inline' pour une fonction/méthode en C++?

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

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

500
Partial

Oh mec, une de mes bêtes noires.

inline ressemble davantage à static ou extern à une directive demandant au compilateur de lier vos fonctions. extern, static, inline sont des directives de liaison utilisées presque exclusivement par l'éditeur de liens, et non par le compilateur.

Il est dit que inline indique au compilateur que la fonction devrait être intégrée. C'était peut-être vrai en 1998, mais une décennie plus tard, le compilateur n'a plus besoin de ces indications. Sans parler des humains, ils ont généralement tort quand il s'agit d'optimiser le code. La plupart des compilateurs ignorent donc totalement le "conseil".

  • static - le nom de variable/fonction ne peut pas être utilisé dans d'autres unités de traduction. L'éditeur de liens doit s'assurer qu'il n'utilise pas accidentellement une variable/fonction définie de manière statique à partir d'une autre unité de traduction.

  • extern - utilisez ce nom de variable/fonction dans cette unité de traduction, mais ne vous plaignez pas s'il n'est pas défini. L'éditeur de liens va le trier et s'assurer que tout le code qui a essayé d'utiliser un symbole externe a son adresse.

  • inline - cette fonction sera définie dans 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 déjà la sémantique de liaison de inline. Toutefois, la spécialisation explicite et l’instanciation des modèles nécessite inline à utiliser.


Réponses spécifiques à vos questions:

  • Quand devrais-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, uniquement 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 seule couche) dans le fichier d'en-tête, car cela fournit au compilateur davantage d'informations à utiliser lors de l'optimisation de 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 inline simplement parce que vous pensez que votre code sera exécuté plus rapidement si le compilateur le met en ligne.

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

    Généralement, le compilateur sera capable de le faire mieux que vous. Cependant, le compilateur n'a pas l'option de code en ligne s'il n'a pas la définition de fonction. Dans le code optimisé au maximum, toutes les méthodes private sont généralement insérées, que vous le demandiez ou non.

    Pour éviter l'inline dans GCC, utilisez __attribute__(( noinline )), et dans Visual Studio, utilisez __declspec(noinline).

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

    Le multithreading n'affecte en aucune façon l'inline.

790
deft_code

J'aimerais contribuer à toutes les bonnes réponses de ce fil en donnant un exemple convaincant pour dissiper tout malentendu subsistant.

Étant donné deux fichiers source, 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:

    Compile :

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

    Output :

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

    Discussion :

    1. Même si vous devez avoir des définitions identiques de vos fonctions inline, le compilateur C++ ne l'indique pas si ce n'est pas le cas (en fait, en raison de compilation séparée il n'a aucun moyen de vérifier il). C'est à vous de le faire!

    2. L'éditeur de liens ne se plaint pas de Une règle de définition , car fun() est déclaré comme inline. Cependant, parce que inline111.cpp est la première unité de traduction (qui appelle en réalité fun()) traitée par le compilateur, le compilateur instancie fun() sur son en premier appel. dans inline111.cpp. Si le compilateur décide pas de développer fun() lors de son appel depuis n'importe quel endroit de votre programme ( eg de inline222.cpp), l'appel à fun() sera toujours lié à son instance produite à partir de inline111.cpp (l'appel à fun() à l'intérieur de inline222.cpp peut également produire une instance dans cette unité de traduction, mais il restera non lié). En effet, cela ressort clairement des impressions &fun = 0x4029a0 identiques.

    3. Enfin, malgré la suggestion inline au compilateur de élargit en fait le fun() à une ligne, il ignore votre suggestion. complètement, ce qui est clair parce que fun() = 111 dans les deux lignes.


  • Cas B:

    Compile (remarquez l'ordre inverse) :

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

    Output :

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

    Discussion :

    1. Ce cas affirme ce qui a été discuté dans Cas A.

    2. Notez un point important, à savoir que si vous commentez l'appel à fun() dans inline222.cpp ( eg commentez cout- instruction dans inline222.cpp complètement) alors, malgré l'ordre de compilation de vos unités de traduction, fun() sera instancié lors de son premier appel dans inline111.cpp, ce qui entraînera une impression pour Cas B comme inline111: fun() = 111, &fun = 0x402980.


  • Cas C:

    Compile (notice -O2) :

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

    ou

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

    Output :

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

    Discussion :

    1. En tant que décrit ici , -O2 optimisation encourage le compilateur à développe réellement les fonctions pouvant être insérées (Notez également que -fno-inline est default sans options d'optimisation). Comme le montre la surimpression ici, la fun() a en fait été inline développé (conformément à sa définition: particulier unité de traduction) , entraînant deux impressions différentes fun(). Malgré cela, il reste toujours un seul instance globalement liée de fun() (comme requis par la norme), comme il ressort de identique &fun impression.
47
Alaroff

Vous devez toujours explicitement insérer votre fonction lors de la spécialisation de modèle (si la spécialisation est dans un fichier .h).

27
BostonLogan

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

2) toujours. Voir n ° 1.

(Édité pour refléter le fait que vous avez divisé votre question en deux questions ...)

18
Aric TenEyck

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 fichier .cpp, vous devez ne pas écrire le mot-clé.

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

Il n'y a pas une telle situation. Le compilateur ne peut pas créer une fonction en ligne. Tout ce que vous pouvez faire est d’inscrire en ligne tout ou partie des 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 qu'une application soit multithread quand on écrit 'inline' pour une fonction/méthode?

Non, cela n'a pas d'importance.

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

Cela dépend du compilateur utilisé. Ne faites pas aveuglément confiance au fait que de nos jours les compilateurs sachent mieux que les humains comment s’inscrire en ligne et que vous ne devriez jamais l’utiliser pour des raisons de performances, car il s’agit d’une directive de liaison plutôt que d’un indice d’optimisation. Bien que je convienne que ces arguments sont justes sur le plan idéologique, la confrontation avec la réalité pourrait être une chose différente.

Après avoir lu plusieurs threads, j’ai essayé par curiosité les effets d’Inline sur le code que je travaillais et les résultats ont été que j’ai obtenu une 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); l'ajout d'inline aux points critiques entraînait une accélération de + 6% avec le code GCC).

Donc, si vous qualifiez GCC 4.6 comme un compilateur moderne, le résultat est que la directive inline a toujours son importance si vous écrivez des tâches gourmandes en temps processeur et savez exactement où se trouve le goulot d'étranglement.

5
meda beda

En réalité, presque jamais. Tout ce que vous faites est de suggérer que le compilateur crée une fonction donnée en ligne (par exemple, remplace tous les appels de cette fonction/son corps). Bien sûr, il n’ya aucune garantie: le compilateur peut ignorer la directive.

Le compilateur détecte et optimise généralement de telles choses.

3
DarkSquid

par défaut, gcc n'inclut aucune fonction lors de la compilation sans optimisation activée. Je ne connais pas Visual Studio - deft_code

J'ai vérifié cela pour Visual Studio 9 (15.00.30729.01) en compilant avec/FAcs et en regardant le code d'assemblage: Le compilateur a généré des appels aux fonctions membres sans optimisation activée en mode débogage. Même si la fonction est marquée avec __ forceinline, aucun code d'exécution en ligne n'est généré.

2
Jedzia

La fonction en ligne C++ est un concept puissant couramment utilisé avec les classes. Si une fonction est en ligne, le compilateur place une copie du code de cette fonction à chaque point où la fonction est appelée au moment de la compilation.

Toute modification apportée à une fonction en ligne pourrait nécessiter la recompilation de tous les clients de la fonction, car le compilateur aurait à remplacer tout le code une fois de plus, sinon les anciennes fonctionnalités continueraient.

Pour intégrer une fonction, placez le mot-clé avant le nom de la fonction et définissez-la avant tout appel à la fonction. Le compilateur peut ignorer le qualificatif inline si la fonction définie est plus qu'une ligne.

Une définition de fonction dans une définition de classe est une définition de fonction inline, même sans l'utilisation du spécificateur inline.

Voici un exemple utilisant la fonction inline pour renvoyer un maximum de deux nombres.

#include <iostream>

using namespace std;

inline int Max(int x, int y) { return (x > y)? x : y; }

// Main function for the program
int main() {
   cout << "Max (100,1010): " << Max(100,1010) << endl;

   return 0;
}

pour plus d'informations, voir here .

1
amirfg

Vous voulez le mettre au tout début, avant de renvoyer le type. Mais la plupart des compilateurs l'ignorent. S'il est défini et qu'il a un bloc de code plus petit, la plupart des compilateurs le considèrent de toute façon en ligne.

0
Jeremy Morgan