273 votes

Avantages des fonctions inline en C++ ?

Quels sont les avantages/inconvénients de l'utilisation des fonctions inline en C++ ? Je vois que cela n'augmente les performances que pour le code que le compilateur produit, mais avec les compilateurs optimisés d'aujourd'hui, les processeurs rapides, la mémoire énorme, etc. (pas comme dans les années 1980< où la mémoire était rare et où tout devait tenir dans 100KB de mémoire), quels avantages ont-elles vraiment aujourd'hui ?

52 votes

C'est l'une de ces questions où la connaissance commune est erronée. Tout le monde a répondu avec la réponse standard de Comp Sci. (L'insertion économise le coût des appels de fonction mais augmente la taille du code). Foutaises. Il fournit un mécanisme simple permettant au compilateur d'appliquer plus d'OPTIMISATIONS.

37 votes

C'est une de ces réponses qui se présentent comme des commentaires. Si vous n'aimez pas une des réponses qui ont été postées, postez votre propre réponse et voyez ce que ça donne.

11 votes

La base de cette question est erronée. Les fonctions en ligne du C++ n'ont pas grand-chose à voir avec les fonctions en ligne des compilateurs lors de la compilation. Il est regrettable que inline est un mot-clé c++ et que l'inlining est une technique d'optimisation du compilateur. Voir cette question " quand dois-je écrire le mot-clé inline pour une fonction/méthode " pour la bonne réponse.

209voto

paercebal Points 38526

Avantages

  • En insérant votre code là où il est nécessaire, votre programme passera moins de temps dans les parties appel de fonction et retour. Cela est censé rendre votre code plus rapide, même s'il devient plus gros (voir ci-dessous). L'insertion d'accesseurs triviaux pourrait être un exemple d'insertion efficace.
  • En la marquant comme inline, vous pouvez placer une définition de fonction dans un fichier d'en-tête (c'est-à-dire qu'elle peut être incluse dans plusieurs unités de compilation, sans que l'éditeur de liens s'en plaigne).

Inconvénients

  • Il peut rendre votre code plus volumineux (par exemple, si vous utilisez l'inline pour les fonctions non triviales). En tant que tel, il pourrait provoquer une pagination et des optimisations défectueuses de la part du compilateur.
  • Cela brise légèrement votre encapsulation car cela expose l'interne de votre traitement d'objet (mais alors, chaque membre "privé" le ferait aussi). Cela signifie que vous ne devez pas utiliser l'inlining dans un pattern PImpl.
  • Cela brise légèrement votre encapsulation 2 : L'encapsulation C++ est résolue au moment de la compilation. Cela signifie que si vous changez le code de la fonction inlined, vous devrez recompiler tout le code qui l'utilise pour être sûr qu'il sera mis à jour (pour la même raison, j'évite les valeurs par défaut pour les paramètres des fonctions).
  • Lorsqu'il est utilisé dans un en-tête, il rend votre fichier d'en-tête plus gros, et donc, dilue les informations intéressantes (comme la liste des méthodes d'une classe) avec du code dont l'utilisateur ne se soucie pas (c'est la raison pour laquelle je déclare les fonctions inlined à l'intérieur d'une classe, mais je les définirai dans un en-tête après le corps de la classe, et jamais à l'intérieur du corps de la classe).

La magie de l'encartage

  • Le compilateur peut ou non mettre en ligne les fonctions que vous avez marquées comme étant en ligne ; il peut également décider de mettre en ligne les fonctions non marquées comme étant en ligne au moment de la compilation ou de la liaison.
  • L'inline fonctionne comme un copier/coller contrôlé par le compilateur, ce qui est très différent d'une macro de pré-processeur : La macro sera inlined de force, polluera tous les espaces de noms et le code, ne sera pas facilement débuggeable, et sera faite même si le compilateur l'aurait jugé inefficace.
  • Toute méthode d'une classe définie à l'intérieur du corps de la classe elle-même est considérée comme "inline" (même si le compilateur peut toujours décider de ne pas l'inline).
  • Les méthodes virtuelles ne sont pas censées être inlinables. Pourtant, parfois, lorsque le compilateur peut connaître avec certitude le type de l'objet (c'est-à-dire que l'objet a été déclaré et construit dans le même corps de fonction), même une fonction virtuelle sera inline car le compilateur connaît exactement le type de l'objet.
  • Les méthodes/fonctions des modèles ne sont pas toujours inlines (leur présence dans un en-tête ne les rend pas automatiquement inlines).
  • L'étape suivante après "inline" est la métaprogrammation de modèles. C'est-à-dire qu'en "inlining" votre code au moment de la compilation, le compilateur peut parfois déduire le résultat final d'une fonction... Ainsi, un algorithme complexe peut parfois être réduit à une sorte de return 42 ; déclaration. Ceci est pour moi intégration extrême . Cela arrive rarement dans la vie réelle, cela allonge le temps de compilation, n'alourdit pas votre code, et rend votre code plus rapide. Mais comme le graal, n'essayez pas de l'appliquer partout car la plupart des traitements ne peuvent être résolus de cette façon... Mais bon, c'est quand même cool...
    -p

0 votes

vous avez dit que ça casse légèrement votre encapsulation. Pouvez-vous l'expliquer à l'aide d'un exemple ?

6 votes

@PravasiMeet : C'est du C++. Disons que vous livrez une DLL/bibliothèque partagée à un client, qui la compile. La fonction inline foo, utilisant la variable membre X et effectuant le travail Y, sera inline dans le code du client. Imaginons que vous ayez besoin de livrer une version mise à jour de votre DLL où vous avez changé la variable membre en Z, et ajouté un travail YY en plus du travail Y. Le client copie simplement la DLL dans son projet, et BOOM, parce que le code de foo dans son binaire n'est pas le code mis à jour que vous avez écrit... Bien que le client n'ait pas d'accès légal à votre code privé, l'inlining le rend tout à fait "public".

0 votes

@paercebal En ce qui concerne votre avant-dernier point, pouvez-vous donner un exemple de cas où un modèle de fonction est pas en ligne ? Je pensais qu'ils étaient toujours en ligne, mais je n'ai pas de référence à portée de main (un simple test semble le confirmer).

150voto

Brian R. Bondy Points 141769

Les fonctions en ligne sont plus rapides parce que vous n'avez pas besoin de pousser et d'enlever des éléments de la pile, comme les paramètres et l'adresse de retour ; cependant, votre binaire est légèrement plus grand.

Cela fait-il une différence significative ? Pas suffisamment sur le matériel moderne pour la plupart des gens. Mais il peut faire une différence, ce qui est suffisant pour certaines personnes.

Le fait de marquer quelque chose en ligne ne vous donne pas la garantie qu'il sera en ligne. C'est juste une suggestion au compilateur. Parfois, ce n'est pas possible, par exemple lorsqu'il s'agit d'une fonction virtuelle, ou lorsqu'il y a récursion. Et parfois, le compilateur choisit simplement de ne pas l'utiliser.

Je pourrais voir une situation comme celle-ci faire une différence détectable :

inline int aplusb_pow2(int a, int b) {
  return (a + b)*(a + b) ;
}

for(int a = 0; a < 900000; ++a)
    for(int b = 0; b < 900000; ++b)
        aplusb_pow2(a, b);

27 votes

Comme je le soupçonnais, l'inlining ne fait aucune différence avec ce qui précède. Compilé avec gcc 4.01. Version 1 forcée à utiliser l'inlining : 48.318u 1.042s 5:51.39 99.4% 0+0k 0+0io 0pf+0w Version 2 forcée sans inlining 348.311u 1.019s 5:52.31 99.1% 0+0k 0+0io 0pf+0w Ceci est un bon exemple où la connaissance commune est fausse.

38 votes

Bien que l'appel lui-même ait effectivement de l'importance, ce n'est que le gain mineur que vous obtenez en utilisant inline. Le gain majeur est que le compilateur voit maintenant où les pointeurs ne s'aliasent pas les uns les autres, où les variables de l'appelant se retrouvent dans le appelé et ainsi de suite. Ainsi, l'optimisation suivante est ce qui importe le plus.

31 votes

Cela ne fait probablement pas de différence dans cet extrait puisque le résultat de la fonction n'est jamais utilisé et que la fonction n'a pas d'effets secondaires. Nous constatons un gain de performance mesurable en inlining dans le traitement des images.

47voto

Emilio Garavaglia Points 9189

En C et C++ archaïque, inline c'est comme register : une suggestion (rien de plus qu'une suggestion) au compilateur sur une optimisation possible.

Dans le C++ moderne, inline indique à l'éditeur de liens que, si plusieurs définitions (pas de déclarations) sont trouvées dans différentes unités de traduction, elles sont toutes identiques, et l'éditeur de liens peut librement en garder une et rejeter toutes les autres.

inline est obligatoire si une fonction (aussi complexe ou "linéaire" soit-elle) est définie dans un fichier d'en-tête, afin de permettre à plusieurs sources de l'inclure sans obtenir une erreur de "définition multiple" par l'éditeur de liens.

Les fonctions membres définies à l'intérieur d'une classe sont "en ligne" par défaut, tout comme les fonctions modèles (contrairement aux fonctions globales).

//fileA.h
inline void afunc()
{ std::cout << "this is afunc" << std::endl; }

//file1.cpp
#include "fileA.h"
void acall()
{ afunc(); }

//main.cpp
#include "fileA.h"
void acall();

int main()
{ 
   afunc(); 
   acall();
}

//output
this is afunc
this is afunc

Notez l'inclusion de fileA.h dans deux fichiers .cpp, ce qui donne deux instances de afunc() . L'éditeur de liens rejettera l'un d'entre eux. Si aucun inline est spécifié, l'éditeur de liens se plaindra.

17voto

paxdiablo Points 341644

La mise en ligne est une suggestion au compilateur qu'il est libre d'ignorer. C'est idéal pour les petits bouts de code.

Si votre fonction est inlined, elle est essentiellement insérée dans le code où l'appel de fonction est effectué, plutôt que d'appeler une fonction séparée. Cela peut contribuer à la rapidité, car vous n'avez pas à effectuer l'appel réel.

Il aide également les processeurs avec le pipelining car ils n'ont pas à recharger le pipeline avec de nouvelles instructions causées par un appel.

Le seul inconvénient est l'augmentation possible de la taille du binaire mais, tant que les fonctions sont petites, cela n'aura pas trop d'importance.

J'ai tendance à laisser ce genre de décisions aux compilateurs de nos jours (en tout cas, les plus intelligents). Les personnes qui les ont écrits ont généralement une connaissance beaucoup plus détaillée des architectures sous-jacentes.

12voto

David Dibben Points 7968

Il y a plusieurs autres questions qui traitent des fonctions en ligne.

http://stackoverflow.com/questions/60830/what-is-wrong-with-using-inline-functions http://stackoverflow.com/questions/86561/inlining-c-code

Quant aux avantages, si vous appelez une petite fonction à partir d'une boucle, cela peut faire une différence significative dans les performances.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X