Quand dois-je écrire le mot-clé inline
d'une fonction / méthode en C ++?
Après avoir vu quelques réponses, quelques questions connexes:
Quand ne devrais-je pas écrire le mot clé 'inline' pour une fonction / méthode en C ++?
Quand le compilateur ne saura-t-il pas quand rendre une fonction / méthode «en ligne»?
Est-ce important si une application est multithread lorsque l'on écrit «en ligne» pour une fonction / méthode?
c++
inline
one-definition-rule
Partiel
la source
la source
inline
(9.3 / 2).Réponses:
Oh mec, une de mes bêtes noires.
inline
ressemble plus àstatic
ouextern
qu’une directive indiquant au compilateur d’aligner vos fonctions.extern
,static
,inline
Sont des directives de liaison, utilisés presque exclusivement par l'éditeur de liens, et non le compilateur.Il est dit que
inline
le compilateur indique que vous pensez que la fonction devrait être intégrée. Cela était peut-être vrai en 1998, mais une décennie plus tard, le compilateur n'a pas besoin de tels indices. Sans oublier que les humains ont généralement tort quand il s'agit d'optimiser le code, donc la plupart des compilateurs ignorent catégoriquement le «conseil».static
- le nom de la 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 statiquement 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 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 dans plusieurs unités de traduction, ne vous en faites 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 liaisoninline
. Cependant, la spécialisation explicite et instanciation des modèles doiventinline
être utilisés.Réponses spécifiques à vos questions:
Uniquement 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 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.
N'ajoutez pas inline simplement parce que vous pensez que votre code s'exécutera plus rapidement si le compilateur l'inline.
Généralement, le compilateur pourra faire cela mieux que vous. Cependant, le compilateur n'a pas la possibilité d'inclure du code s'il n'a pas la définition de fonction. Dans le code optimisé au maximum, toutes les
private
méthodes sont généralement intégrées, que vous le demandiez ou non.En aparté pour empêcher l'incrustation dans GCC, utilisez
__attribute__(( noinline ))
et dans Visual Studio, utilisez__declspec(noinline)
.Le multithreading n'affecte en rien l'inline.
la source
inline
mot-clé ne sont pas liés. Vous avez cependant la bonne idée. En règle générale, deviner ce qui serait amélioré par l'inlining est très sujet aux erreurs. L'exception à cette règle étant une ligne.Je voudrais contribuer à toutes les bonnes réponses de ce fil avec un exemple convaincant pour dissiper tout malentendu.
Étant donné deux fichiers source, tels que:
inline111.cpp:
inline222.cpp:
Cas A:
Compiler :
Sortie :
Discussion :
Même si vous devez avoir des définitions identiques de vos fonctions en ligne, le compilateur C ++ ne le marque pas si ce n'est pas le cas (en fait, en raison de la compilation séparée, il n'a aucun moyen de le vérifier). Il est de votre devoir de vous en assurer!
L'éditeur de liens ne se plaint pas d' une règle de définition unique , comme il
fun()
est déclaréinline
. Cependant, comme inline111.cpp est la première unité de traduction (qui appelle en faitfun()
) traitée par le compilateur, le compilateur instanciefun()
lors de sa première rencontre d'appel dans inline111.cpp . Si le compilateur décide de ne pas développerfun()
son appel de n'importe où ailleurs dans votre programme ( par exemple à partir de inline222.cpp ), l'appel àfun()
sera toujours lié à son instance produite à partir de inline111.cpp (l'appel à l'fun()
intérieur de inline222.cpppeut également produire une instance dans cette unité de traduction, mais elle ne sera pas liée). En effet, cela ressort des&fun = 0x4029a0
impressions identiques .Enfin, malgré la
inline
suggestion faite au compilateur d' étendre réellement le one-linerfun()
, il ignore complètement votre suggestion, ce qui est clair carfun() = 111
dans les deux lignes.Cas B:
Compiler (notez l'ordre inverse) :
Sortie :
Discussion :
Cette affaire affirme ce qui a été discuté dans le cas A .
Remarquez un point important, que si vous commentez l'appel réel à
fun()
en inline222.cpp ( par exemple un commentaire surcout
-Déclaration dans inline222.cpp complètement) puis, malgré l'ordre de compilation de vos unités de traduction,fun()
sera instancié sur sa première rencontre d'appel en inline111.cpp , résultant en une impression pour le cas B en tant queinline111: fun() = 111, &fun = 0x402980
.Cas C:
Compiler (notice -O2) :
ou
Sortie :
Discussion :
-O2
optimisation encourage le compilateur à réellement étendre les fonctions qui peuvent être intégrées (notez également qu'il-fno-inline
s'agit par défaut sans options d'optimisation). Comme il ressort de l'outprint ici, lefun()
a été en fait développé en ligne (selon sa définition dans cette unité de traduction particulière ), résultant en deux impressions différentesfun()
. Malgré cela, il n'y a toujours qu'une seule instance liée à l'échelle mondialefun()
(comme l'exige la norme), comme le montre une&fun
impression identique .la source
inline
fonctions un comportement indéfini..cpp
étant sa propre unité de traduction. De préférence, ajoutez des cas pour-flto
activé / désactivé.Vous devez toujours explicitement inline votre fonction lors de la spécialisation de modèle (si la spécialisation est dans le fichier .h)
la source
1) De nos jours, presque jamais. Si c'est une bonne idée d'inline une fonction, le compilateur le fera sans votre aide.
2) Toujours. Voir # 1.
(Modifié pour refléter le fait que vous avez divisé votre question en deux questions ...)
la source
inline
est toujours nécessaire, par exemple pour définir une fonction dans un fichier d'en-tête (et qui est nécessaire pour intégrer une telle fonction dans plusieurs unités de compilation).inline
spécificateur, ses instances sont automatiquement réduites en une par l'éditeur de liens et ODR n'est pas utilisé.Si la fonction est déclarée dans l'en-tête et définie dans le
.cpp
fichier, vous ne devez pas écrire le mot-clé.Il n'y a pas une telle situation. Le compilateur ne peut pas rendre une fonction inline. Tout ce qu'il peut faire, c'est d'incorporer 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 le peut).
Non, cela n'a pas d'importance du tout.
la source
Cela dépend du compilateur utilisé. Ne vous fiez pas aveuglément au fait que de nos jours, les compilateurs savent mieux que les humains comment s'aligner et 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 que ces arguments sont idéologiquement corrects, rencontrer la réalité pourrait être une chose différente.
Après avoir lu plusieurs fils autour, j'ai essayé par curiosité les effets de l'inline sur le code sur lequel je travaille 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 en ligne aux points critiques a provoqué une accélération 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 gourmandes en CPU et savez où se trouve exactement le goulot d'étranglement.
la source
En réalité, presque jamais. Tout ce que vous faites, c'est suggérer que le compilateur fasse une fonction donnée en ligne (par exemple, remplace tous les appels à cette fonction / w son corps). Il n'y a bien sûr aucune garantie: le compilateur peut ignorer la directive.
Le compilateur fera généralement un bon travail pour détecter + optimiser des choses comme ça.
la source
inline
a une différence sémantique en C ++ (par exemple dans la façon dont plusieurs définitions sont traitées), ce qui est important dans certains cas (par exemple les modèles).J'ai vérifié cela pour Visual Studio 9 (15.00.30729.01) en compilant avec / FAcs et en regardant le code d'assembly: le compilateur a produit 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é.
la source
Vous voulez le mettre au tout début, avant de retourner 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.
la source
Sauf si vous écrivez une bibliothèque ou avez des raisons particulières, vous pouvez oublier
inline
et utiliser à la place l' optimisation du lien . Il supprime l'exigence selon laquelle une définition de fonction doit être dans un en-tête pour qu'elle soit prise en compte pour l'inclusion dans les unités de compilation, ce qui est précisément ce quiinline
permet.(Mais voir Y a - t-il une raison pour ne pas utiliser l'optimisation du temps de liaison? )
la source
Le mot clé en ligne demande au compilateur de remplacer l'appel de fonction par le corps de la fonction, il évalue d'abord l'expression, puis le transmet, ce qui réduit la surcharge de l'appel de fonction car il n'est pas nécessaire de stocker l'adresse de retour et la mémoire de pile n'est pas requise pour la fonction arguments.
Quand utiliser:
la source
inline
ou non en C et C ++. C Inline: stackoverflow.com/a/62287072/7194773 C ++ inline: stackoverflow.com/a/62230963/7194773C ++ inline est totalement différent de C inline .
inline
affecte à lui seul le compilateur, l'assembleur et l'éditeur de liens. Il s'agit d'une directive adressée au compilateur disant de n'émettre un symbole pour cette fonction / donnée que si elle est utilisée dans l'unité de traduction, et si c'est le cas, alors comme les méthodes de classe, dites à l'assembleur de les stocker dans la section.section .text.c::function(),"axG",@progbits,c::function(),comdat
ou.section .bss.i,"awG",@nobits,i,comdat
pour les données. Les instanciations de modèles vont également dans leurs propres groupes comdat.Cela suit
.section name, "flags"MG, @type, entsize, GroupName[, linkage]
. Par exemple, le nom de la section est.text.c::function()
.axG
signifie que la section est allouable, exécutable et dans un groupe, c'est-à-dire qu'un nom de groupe sera spécifié (et il n'y a pas d'indicateur M, donc aucune dimension ne sera spécifiée);@progbits
signifie que la section contient des données et n'est pas vide;c::function()
est le nom du groupe et le groupe acomdat
liaison signifiant que dans tous les fichiers objets, toutes les sections rencontrées avec ce nom de groupe étiqueté avec comdat seront supprimées de l'exécutable final sauf 1 c'est-à-dire que le compilateur s'assure qu'il n'y a qu'une seule définition dans l'unité de traduction et dit ensuite à l'assembleur de mettre dans son propre groupe dans le fichier objet (1 section dans 1 groupe), puis l'éditeur de liens s'assurera que si des fichiers objet ont un groupe du même nom, n'en incluez qu'un dans le fichier .exe final. La différence entreinline
et ne pas utiliserinline
est maintenant visible par l'assembleur et par conséquent l'éditeur de liens, car il n'est pas stocké dans le régulier.data
ou.text
etc. par l'assembleur en raison de leurs directives.static inline
dans une classe signifie qu'il s'agit d'une définition de type et non d'une déclaration (permet de définir un membre statique dans la classe) et de le rendre en ligne; il se comporte maintenant comme ci-dessus.static inline
à la portée du fichier affecte uniquement le compilateur. Cela signifie pour le compilateur: n'émettre un symbole pour cette fonction / donnée que s'il est utilisé dans l'unité de traduction et le faire comme un symbole statique régulier (stocker dans.text /.data sans directive .globl). Pour l'assembleur, il n'y a plus de différence entrestatic
etstatic inline
extern inline
est une déclaration qui signifie que vous devez définir ce symbole dans l'unité de traduction ou jeter l'erreur du compilateur; s'il est défini, traitez-le comme un normalinline
et pour l'assembleur et l'éditeur de liens, il n'y aura pas de différence entreextern inline
etinline
, il s'agit donc uniquement d'une protection du compilateur.L'ensemble de ce qui précède sans la ligne d'erreur s'effondre
inline int i[5]
. Il est évident que si vous avezextern inline int i[] = {5};
alorsextern
serait ignorée en raison de la définition explicite par voie de cession.inline
sur un espace de noms, voyez ceci et celala source
Lors du développement et du débogage de code, omettez
inline
. Cela complique le débogage.La raison principale de leur ajout est d'aider à optimiser le code généré. En règle générale, cela échange un espace de code accru contre de la vitesse, mais
inline
économise parfois à la fois l'espace de code et le temps d'exécution.Développer ce type de réflexion sur l'optimisation des performances avant la fin de l'algorithme est une optimisation prématurée .
la source
inline
les fonctions ne sont généralement pas intégrées, sauf si elles sont compilées avec des optimisations, elles n'affectent donc en aucune façon le débogage. N'oubliez pas que c'est un indice, pas une demande.inline
fonctions ont été intégrées. Il était impossible de définir un point d'arrêt significatif en eux.inline
ne fera rien pour améliorer le code sur un compilateur moderne, qui peut déterminer s'il doit être intégré ou non par lui-même.Quand faut-il s'aligner:
1.Lorsque l'on veut éviter les frais généraux qui se produisent lorsque la fonction est appelée comme le passage de paramètres, le transfert de contrôle, le retour de contrôle, etc.
2.La fonction doit être petite, souvent appelée et la mise en ligne est vraiment avantageuse car, conformément à la règle 80-20, essayez de rendre ces fonctions en ligne qui ont un impact majeur sur les performances du programme.
Comme nous le savons, l'inline n'est qu'une demande au compilateur similaire à l'inscription et cela vous coûtera à la taille du code objet.
la source
inline
a perdu son statut d'indicateur d'optimisation, et la plupart des compilateurs ne l'utilisent que pour tenir compte de plusieurs définitions - comme l'OMI le devrait. Plus encore, depuis C ++ 11,register
a été complètement déconseillé pour sa signification antérieure de `` Je sais mieux que le compilateur comment optimiser '': c'est maintenant juste un mot réservé sans signification actuelle.inline
une certaine mesure.La fonction en ligne C ++ est un concept puissant qui est 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 d'une fonction en ligne peut nécessiter la recompilation de tous les clients de la fonction car le compilateur devra remplacer à nouveau tout le code, sinon il continuera avec les anciennes fonctionnalités.
Pour incorporer une fonction, placez le mot clé inline avant le nom de la fonction et définissez la fonction avant tout appel à la fonction. Le compilateur peut ignorer le qualificatif en ligne dans le cas où 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 en ligne, même sans l'utilisation du spécificateur en ligne.
Voici un exemple, qui utilise la fonction inline pour renvoyer un maximum de deux nombres
pour plus d'informations, voir ici .
la source