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?
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);
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 ...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.
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.
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.
Il ne nécessite pas de temps système d’appel de fonction.
Cela évite également les frais généraux des variables Push/pop sur la pile, tout en appelant une fonction.
Cela évite également les frais généraux liés aux appels de retour d'une fonction.
Il augmente la localité de référence en utilisant le cache d’instruction.
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
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.
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.
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.
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.
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.
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.
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.
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.