web-dev-qa-db-fra.com

Avantages des fonctions inline en C ++?

Quels sont les avantages/inconvénients de l'utilisation de fonctions inline en C++? Je constate que cela n'augmente que les performances du code fourni par le compilateur, mais avec les compilateurs optimisés actuels, les processeurs rapides, la mémoire énorme, etc. avantages ont-ils vraiment aujourd'hui?

249
Lennie De Villiers

Les fonctions en ligne sont plus rapides car vous n'avez pas besoin d'insérer et de déposer des éléments dans la pile, comme des paramètres et l'adresse de retour; Cependant, cela rend votre binaire légèrement plus grand.

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

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

Je pouvais voir une telle situation 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);
139
Brian R. Bondy

Avantages

  • En alignant votre code là où il est nécessaire, votre programme passera moins de temps dans l'appel de fonction et le renvoi des pièces. Il est supposé rendre votre code plus rapide, même s'il est volumineux (voir ci-dessous). L'inclusion d'accesseurs triviaux pourrait être un exemple d'inline efficace.
  • En le marquant comme étant en ligne, 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 se plaint).

Désavantages

  • Cela peut rendre votre code plus gros (c'est-à-dire si vous utilisez inline pour des fonctions non triviales). En tant que tel, cela pourrait provoquer une pagination et empêcher les optimisations du compilateur.
  • Cela casse légèrement votre encapsulation car cela expose l’interne du traitement de votre objet (mais chaque membre "privé" le serait aussi). Cela signifie que vous ne devez pas utiliser l'inline dans un modèle PImpl.
  • Cela casse légèrement votre encapsulation 2: l'inline C++ est résolue au moment de la compilation. Cela signifie que si vous modifiez le code de la fonction intégrée, vous devrez recompiler tout le code en l'utilisant pour vous assurer qu'il sera mis à jour (pour la même raison, j'évite les valeurs par défaut pour les paramètres de la fonction).
  • Utilisé dans un en-tête, il agrandit votre fichier d’en-tête et dilue ainsi les informations intéressantes (comme la liste des méthodes de classe) avec du code qui ne tient pas à l’utilisateur (c’est la raison pour laquelle je déclare des fonctions en ligne dans un fichier. classe, mais le définira dans un en-tête après le corps de la classe, et jamais à l'intérieur du corps de la classe).

Magie en ligne

  • Le compilateur peut ou non intégrer les fonctions que vous avez marquées comme telles; il peut également décider d’utiliser des fonctions inline non marquées comme telles lors de la compilation ou de la création de liens.
  • Inline fonctionne comme un copier/coller contrôlé par le compilateur, ce qui est assez différent d'une macro pré-processeur: la macro sera forcée en ligne, polluera tous les espaces de noms et le code, ne sera pas facilement mise au point et sera exécutée même si le compilateur l'aurait jugé inefficace.
  • Toute méthode d'une classe définie dans le corps même de la classe est considérée comme "en ligne" (même si le compilateur peut toujours décider de ne pas la mettre en ligne).
  • Les méthodes virtuelles ne sont pas supposées être en ligne. Cependant, 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 en ligne car le compilateur connaît exactement le type de l’objet.
  • Les méthodes/fonctions de modèle ne sont pas toujours en ligne (leur présence dans un en-tête ne les rendra pas automatiquement en ligne).
  • La prochaine étape après "inline" est la métaprogrammation des modèles. C'est à dire. En "alignant" votre code lors 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 d'instruction return 42 ;. C'est pour moi extrême en ligne. Cela arrive rarement dans la vie réelle, cela rallonge le temps de compilation, ne gonfle pas votre code et le rend plus rapide. Mais comme pour le graal, n'essayez pas de l'appliquer partout car la plupart des traitements ne peuvent pas être résolus de cette façon ... Pourtant, c'est quand même cool ...
    :-p
195
paercebal

En C et C++ archaïques, inline ressemble à register: une suggestion (rien de plus qu'une suggestion) au compilateur concernant une optimisation possible.

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

inline est obligatoire si une fonction (quelle que soit sa complexité ou son caractère "linéaire") est définie dans un fichier d'en-tête afin de permettre à plusieurs sources de l'inclure sans générer d'erreur "de multiples définitions" de la part de l'éditeur de liens.

Les fonctions membres définies dans une classe sont "inline" par défaut, de même que les fonctions de modèle (par opposition 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 éliminera l'un d'entre eux. Si aucun inline n'est spécifié, l'éditeur de liens se plaindra.

41
Emilio Garavaglia

L'inclusion est une suggestion au compilateur qu'il est libre d'ignorer. C'est idéal pour les petits morceaux de code.

Si votre fonction est en ligne, elle est essentiellement insérée dans le code où l'appel de fonction est effectué, plutôt que d'appeler une fonction distincte. Cela peut aider avec la rapidité car vous n'avez pas à faire l'appel réel.

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

Le seul inconvénient est l’augmentation de la taille binaire, mais tant que les fonctions sont petites, cela n’a aucune importance.

J'ai tendance à laisser ce genre de décisions aux compilateurs de nos jours (enfin, les plus intelligents de toute façon). Les personnes qui les ont écrites ont tendance à avoir une connaissance beaucoup plus détaillée des architectures sous-jacentes.

16
paxdiablo

La fonction en ligne est la technique d'optimisation utilisée par les compilateurs. On peut simplement ajouter le mot-clé inline au prototype de fonction pour créer une fonction en ligne. La fonction inline demande au compilateur d’insérer le corps complet de la fonction chaque fois que cette fonction est utilisée dans le code.

Avantages: -

  1. Il ne nécessite pas de temps système d’appel de fonction.

  2. Cela évite également les frais généraux des variables Push/pop sur la pile, tout en appelant une fonction.

  3. Cela évite également les frais généraux liés aux appels de retour d'une fonction.

  4. Il augmente la localité de référence en utilisant le cache d’instruction.

  5. Une fois que le compilateur est en ligne, il peut également appliquer une optimisation intra-procédure, si spécifié. C’est le plus important, de cette manière le compilateur peut désormais se concentrer sur l’élimination du code mort, peut accentuer la prédiction de branche, l’élimination des variables d’induction, etc.

Pour en savoir plus, suivez ce lien http://tajendrasengar.blogspot.com/2010/03/what-is-inline-function-in-cc.html

12
TSS

J'aimerais ajouter que les fonctions en ligne sont cruciales lorsque vous construisez une bibliothèque partagée. Sans marquer la fonction en ligne, il sera exporté dans la bibliothèque sous forme binaire. Il sera également présent dans la table des symboles, s'il est exporté. De l'autre côté, les fonctions en ligne ne sont pas exportées, ni dans les fichiers binaires de la bibliothèque, ni dans la table des symboles.

Cela peut être critique lorsque la bibliothèque doit être chargée au moment de l'exécution. Il peut également toucher les bibliothèques compatibles binaires. Dans de tels cas, n'utilisez pas inline.

6
doc

Lors de l'optimisation, de nombreux compilateurs utiliseront des fonctions en ligne, même si vous ne les avez pas marqués. En général, vous n'avez besoin de marquer les fonctions en ligne que si vous savez que le compilateur ne le sait pas, car il peut généralement prendre la bonne décision lui-même.

4
Devrin

inline vous permet de placer une définition de fonction dans un fichier d'en-tête et #include ce fichier d'en-tête dans plusieurs fichiers source sans enfreindre la règle de définition unique.

4
Ferruccio

Tout n’est pas question de performance. C++ et C sont utilisés pour la programmation intégrée, assis au-dessus du matériel. Si vous voulez, par exemple, écrire un gestionnaire d'interruption, vous devez vous assurer que le code peut être exécuté en une fois, sans que des registres supplémentaires et/ou des pages de mémoire ne soient échangés. C'est à ce moment qu'Inline devient pratique. Les bons compilateurs font des "alignements" quand la vitesse est nécessaire, mais "inline" les oblige.

3
J.M. Stoorvogel

De manière générale, de nos jours, tous les compilateurs modernes qui s’inquiètent de tout aligner sont une perte de temps. Le compilateur devrait en réalité optimiser toutes ces considérations pour vous grâce à sa propre analyse du code et à votre spécification des indicateurs d'optimisation transmis au compilateur. Si vous vous souciez de la vitesse, dites au compilateur d'optimiser la vitesse. Si vous vous souciez de l'espace, demandez au compilateur d'optimiser l'espace. Comme une autre réponse évoquée, un compilateur décent sera même automatiquement en ligne si cela a du sens.

En outre, comme d’autres l’ont déjà dit, utiliser inline ne garantit en aucun cas inline. Si vous voulez le garantir, vous devrez définir une macro au lieu d'une fonction en ligne pour le faire.

Quand intégrer et/ou définir une macro pour forcer l'inclusion? - Ce n'est que lorsque vous avez une augmentation prouvée et nécessaire prouvée de la vitesse pour une section de code critique connue pour avoir une incidence sur les performances globales de l'application.

3
Tall Jeff

Notre professeur d'informatique nous a exhorté à ne jamais utiliser inline dans un programme c ++. Lorsqu'on lui a demandé pourquoi, il a gentiment expliqué que les compilateurs modernes devaient détecter quand utiliser inline automatiquement.

Alors oui, l'inline peut être une technique d'optimisation à utiliser dans la mesure du possible, mais apparemment, c'est quelque chose qui est déjà fait pour vous chaque fois qu'il est possible d'intégrer une fonction de toute façon.

1
HumbleWebDev

Vous avez le même problème avec l’inclusion de fonctions dans des bibliothèques. Il semble que les fonctions en ligne ne sont pas compilées dans la bibliothèque. par conséquent, l'éditeur de liens génère une erreur de "référence non définie" si un exécutable souhaite utiliser la fonction intégrée de la bibliothèque. (m'est arrivé de compiler la source Qt avec gcc 4.5.

1
Martin Wilde

Pourquoi ne pas rendre toutes les fonctions en ligne par défaut? Parce que c'est un compromis d'ingénierie. Il existe au moins deux types "d'optimisation": accélérer le programme et réduire la taille (empreinte mémoire) du programme. La mise en ligne accélère généralement les choses. Il supprime les frais généraux liés aux appels de fonctions, évitant de pousser puis d'extraire des paramètres de la pile. Cependant, l'encombrement de la mémoire du programme est également plus important, car chaque appel de fonction doit maintenant être remplacé par le code complet de la fonction. Pour compliquer encore les choses, rappelez-vous que la CPU stocke des fragments de mémoire fréquemment utilisés dans un cache sur la CPU pour un accès ultra-rapide. Si vous agrandissez suffisamment l'image mémoire du programme, celui-ci ne pourra pas utiliser efficacement le cache et, dans le pire des cas, l'inline risque de ralentir votre programme. Dans une certaine mesure, le compilateur peut calculer les compromis et être en mesure de prendre de meilleures décisions que vous ne le pouvez, en regardant simplement le code source.

1
mehrdad zomorodiyan