web-dev-qa-db-fra.com

Quand utiliser la fonction en ligne et quand ne pas l'utiliser?

Je sais que inline est un indice ou une requête du compilateur et qu’il est utilisé pour éviter les frais généraux d’appel de fonction.

Alors, sur quelle base peut-on déterminer si une fonction peut être ou non en ligne? Dans quel cas devrait-on éviter l'inline?

167
Ashish

Éviter le coût d'un appel de fonction n'est que la moitié de l'histoire.

faire:

  • utilisez inline au lieu de #define
  • de très petites fonctions sont de bonnes candidates pour inline: code plus rapide et exécutables plus petits (plus de chances de rester dans le cache de code)
  • la fonction est petite et appelée très souvent

ne pas:

  • fonctions volumineuses: conduit à des fichiers exécutables plus volumineux, ce qui nuit considérablement aux performances, quelle que soit l'exécution plus rapide résultant du temps système supplémentaire
  • fonctions en ligne liées aux entrées/sorties
  • la fonction est rarement utilisée
  • constructeurs et destructeurs: même vides, le compilateur génère un code pour eux
  • rupture de la compatibilité binaire lors du développement de bibliothèques:
    • inline une fonction existante
    • modifier une fonction en ligne ou rendre une fonction en ligne non en ligne: la version précédente de la bibliothèque appelle l'ancienne implémentation

lors du développement d'une bibliothèque, pour rendre une classe extensible à l'avenir, vous devez:

  • ajouter un destructeur virtuel non en ligne même si le corps est vide
  • rendre tous les constructeurs non-inline
  • écrire des implémentations non inline du constructeur de copie et de l'opérateur d'affectation, sauf si la classe ne peut pas être copiée par valeur

Rappelez-vous que le mot-clé inline est un indice pour le compilateur: le compilateur peut décider de ne pas intégrer une fonction et il peut décider d'inclure des fonctions non marquées inline. J'évite généralement de marquer les fonctions inline (sauf peut-être lors de l'écriture de très petites fonctions).

En ce qui concerne les performances, l’approche sage consiste (comme toujours) à profiler l’application, puis finalement inline un ensemble de fonctions représentant un goulot d’étranglement.

Références:


EDIT: Bjarne Stroustrup, Le langage de programmation C++:

Une fonction peut être définie comme étant inline. Par exemple:

inline int fac(int n)
{
  return (n < 2) ? 1 : n * fac(n-1);
}

Le spécificateur inline indique au compilateur qu'il doit tenter de générer du code pour un appel de fac() inline plutôt que de définir le code de la fonction une fois, puis de passer par la fonction habituelle. mécanisme d'appel. Un compilateur intelligent peut générer la constante 720 Pour un appel fac(6). La possibilité de fonctions inline mutuellement récursives, fonctions inline qui récidivent ou non en fonction des entrées, etc., empêche de garantir que chaque appel d'une fonction inline est réellement en ligne. Le degré d'ingéniosité d'un compilateur ne pouvant être légiféré, un compilateur peut générer 720, Un autre 6 * fac(5) et encore un autre appel non en ligne fac(6).

Pour permettre l'inline en l'absence de fonctionnalités de compilation et de liaison particulièrement astucieuses, la définition - et pas seulement la déclaration - d'une fonction inline doit être incluse (§9.2). Un especifier inline n'affecte pas la sémantique d'une fonction. En particulier, une fonction inline a toujours une adresse unique, de même que static variables (§7.1.2) d'une fonction inline.

EDIT2: ISO-IEC 14882-1998, 7.1.2 Spécificateurs de fonction

Une déclaration de fonction (8.3.5, 9.3, 11.4) avec un spécificateur inline déclare une fonction inline. Le spécificateur en ligne indique à l'implémentation que la substitution en ligne du corps de la fonction au point d'appel doit être préférée au mécanisme d'appel de fonction habituel. Une implémentation n'est pas nécessaire pour effectuer cette substitution en ligne au point d'appel; Cependant, même si cette substitution en ligne est omise, les autres règles pour les fonctions en ligne définies en 7.1.2 doivent toujours être respectées.

195
Gregory Pakosz

inline a très peu à voir avec l'optimisation. inline est une instruction à donner au compilateur pour ne pas produire d'erreur si la fonction donnée est définie plusieurs fois dans le programme et une promesse que la définition apparaîtra dans chaque traduction utilisée et qu'elle paraîtra partout ont exactement la même définition.

Compte tenu des règles ci-dessus, inline convient aux fonctions courtes dont le corps ne nécessite pas l'inclusion de dépendances supplémentaires par rapport à ce dont une déclaration aurait besoin. Chaque fois que la définition est rencontrée, elle doit être analysée et le code de son corps peut être généré, ce qui implique une surcharge du compilateur par rapport à une fonction définie une seule fois dans un seul fichier source.

Un compilateur peut en ligne (c.-à-d. Remplacer un appel à la fonction par un code qui exécute cette action de cette fonction) à n’importe quel appel de fonction qu’il choisit. Auparavant, il était "évidemment" impossible de mettre en ligne une fonction qui n'était pas déclarée dans la même unité de traduction que l'appel mais avec l'utilisation croissante de l'optimisation du temps de liaison, même si ce n'est plus le cas à présent. Il est également vrai que les fonctions marquées inline ne peuvent pas être en ligne.

55
CB Bailey

Dire au compilateur d'inline une fonction est une optimisation, et la règle la plus importante de l'optimisation est que l'optimisation prématurée est la racine de tous les maux. Écrivez toujours du code clair (en utilisant des algorithmes efficaces), puis profilez votre programme et optimisez uniquement les fonctions qui prennent trop de temps.

Si vous trouvez qu'une fonction particulière est très courte et simple, et qu'elle s'appelle des dizaines de milliers de fois en boucle intérieure étroite, elle pourrait être un bon candidat.

Vous serez peut-être surpris, cependant, de nombreux compilateurs C++ incorporeront automatiquement de petites fonctions en ligne, et ignoreront également votre demande.

10
dmazzoni

La meilleure façon de le savoir est de profiler votre programme et de marquer les petites fonctions souvent appelées et de graver des cycles de la CPU comme inline. Le mot clé ici est "petit" - une fois que la surcharge de l'appel de fonction est négligeable par rapport au temps passé dans la fonction, il est inutile de les en-ligne.

L’autre utilisation que je vous suggérerais est que si vous avez suffisamment de petites fonctions appelées dans un code critique de performances assez souvent pour rendre un cache manquant d’importance, vous devriez probablement les y intégrer également. Encore une fois, le profileur devrait pouvoir vous le dire.

5
Timo Geusch

L'optimisation prématurée est la racine de tout Mal!

En règle générale, d'habitude, je n'insère que des "getters" et des "setters". Une fois que le code fonctionne et qu'il est stable, le profilage peut indiquer quelles fonctions pourraient bénéficier de l'intégration en ligne.

D'autre part, la plupart des compilateurs modernes ont de très bons algorithmes d'optimisation et indiqueront ce que vous devriez avoir en ligne.

Reasuming - écrivez des fonctions en une ligne, et vous inquiétez pour les autres plus tard.

4
Kornel Kisielewicz

Les fonctions en ligne pourraient améliorer les performances de votre code en éliminant le besoin de placer des arguments dans la pile. si la fonction en question est dans une partie critique de votre code, vous devez prendre la décision inline et inline dans la partie optimisation de votre projet,

vous pouvez en savoir plus sur les inlines dans c ++ faq

2
Alon

J'utilise souvent des fonctions inline non comme une optimisation mais pour rendre le code plus lisible. Parfois, le code lui-même est plus court et plus facile à comprendre que les commentaires, les noms descriptifs, etc. Par exemple:

void IncreaseCount() { freeInstancesCnt++; }

Le lecteur connaît immédiatement la sémantique complète du code.

1
danatel

Je suis généralement une règle du pouce où je fais une fonction avec 3-4 déclarations simples en ligne. Mais il est bon de se rappeler qu’il s’agit simplement d’un indice pour le compilateur. Le dernier appel à le mettre en ligne ou non est pris uniquement par le compilateur. S'il y a plus que ces nombreuses déclarations, je ne déclarerai pas inline comme avec un compilateur stupide, cela peut conduire à un gonflement du code.

0
Naveen

Le meilleur moyen serait d'examiner et de comparer les instructions générées pour les modifications en ligne et non en ligne. Cependant, il est toujours prudent d'omettre inline. Utiliser inline pourrait vous causer des problèmes.

0
wallyk

Lorsque je décide d'utiliser ou non Inline, je garde généralement à l'esprit l'idée suivante: sur les machines modernes, le temps de latence de la mémoire peut constituer un goulot d'étranglement plus important que les calculs bruts. L'inclusion de fonctions appelées souvent est connue pour augmenter la taille de l'exécutable. En outre, une telle fonction pourrait être stockée dans la mémoire cache du code de la CPU, ce qui diminuera le nombre d'occurrences manquées dans la mémoire cache lorsqu'il faudra accéder à ce code.

Par conséquent, vous devez décider vous-même: l’intégration augmente-t-elle ou diminue-t-elle la taille du code machine généré? Quelle est la probabilité que l’appel de la fonction provoque l’absence de mémoire cache? Si cela se retrouve dans le code, je dirais que la probabilité est élevée. Si elle se limite à une seule boucle étroite, la probabilité est faible, espérons-le.

J'utilise généralement l'inline dans les cas énumérés ci-dessous. Cependant, lorsque vous êtes réellement préoccupé par les performances, le profilage est essentiel. De plus, vous voudrez peut-être vérifier si le compilateur prend réellement l’indice.

  • Des routines courtes appelées dans une boucle serrée.
  • Accesseurs très basiques (get/set) et fonctions wrapper.
  • Le code de modèle dans les fichiers d'en-tête obtient malheureusement automatiquement l'indicateur en ligne.
  • Code court utilisé comme une macro. (Exemple: min ()/max ())
  • Courtes routines de mathématiques.
0
Rehno Lindeque

Vous devez utiliser le qualificateur de fonction inline uniquement lorsque le code de la fonction est petit.Si les fonctions sont plus grandes, préférez les fonctions normales, car économiser de la mémoire vaut le sacrifice relativement petit de la vitesse d'exécution.

0
nitish

En outre, une méthode en ligne a des effets secondaires graves lors de la maintenance de grands projets. Lorsque le code en ligne est modifié, tous les fichiers qui l'utilisent seront reconstruits automatiquement par le compilateur (c'est un bon compilateur). Cela pourrait vous faire perdre beaucoup de temps de développement.

Lorsqu'une méthode inline est transférée dans un fichier source et n'est plus alignée, le projet entier doit être reconstruit (du moins c'est mon expérience). Et aussi lorsque les méthodes sont converties en ligne.

0
Thomas Matthews

Lorsque vous pensez que votre code est suffisamment petit pour être utilisé en ligne et que vous vous souvenez de la fonction en ligne, dupliquez-le et collez-le lorsque la fonction est appelée. Il peut donc être suffisant pour augmenter votre temps d'exécution, mais aussi votre consommation de mémoire. Vous ne pouvez pas utiliser la fonction inline lorsque vous utilisez une fonction boucle/variable statique/récursive/commutateur/goto/virtuelle. Virtuel signifie attendre jusqu'à l'exécution et inline pendant la compilation pour ne pas pouvoir être utilisé simultanément.

0
sachin pathak