- Article
Le mot clé inline
indique au compilateur de substituer le code dans la définition de fonction pour chaque instance d'un appel de fonction.
L'utilisation des fonctions inline permet accélérer l'exécution de votre programme, car celles-ci éliminent la surcharge associée aux appels de fonction. Le compilateur peut optimiser les fonctions développées inline de manière non disponible pour les fonctions normales.
La substitution de code inline se produit à la discrétion du compilateur. Par exemple, le compilateur n'inclut pas une fonction si son adresse est prise ou si elle trop volumineuse pour être incluse.
Une fonction définie dans le corps d’une déclaration de classe est implicitement une fonction inline.
Exemple
Dans la déclaration de classe suivante, le constructeur Account
est une fonction inline. Les fonctions GetBalance
membres , Deposit
et Withdraw
ne sont pas spécifiées en tant que inline
mais peuvent être implémentées en tant que fonctions inline.
// Inline_Member_Functions.cppclass Account{public: Account(double initial_balance) { balance = initial_balance; } double GetBalance(); double Deposit( double Amount ); double Withdraw( double Amount );private: double balance;};inline double Account::GetBalance(){ return balance;}inline double Account::Deposit( double Amount ){ return ( balance += Amount );}inline double Account::Withdraw( double Amount ){ return ( balance -= Amount );}int main(){}
Notes
Dans la déclaration de classe, les fonctions ont été déclarées sans le inline
mot clé. Le inline
mot clé peut être spécifié dans la déclaration de classe ; le résultat est le même.
Une fonction membre inline donnée doit être déclarée de la même manière dans chaque unité de compilation. Cette contrainte entraîne les fonctions inline à se comporter comme si elles étaient des fonctions instanciées. En outre, il doit exister une seule définition d'une fonction inline.
Une fonction membre de classe utilise par défaut une liaison externe, sauf si une définition de cette fonction contient le inline
spécificateur. L’exemple précédent montre que vous n’avez pas besoin de déclarer ces fonctions explicitement avec le inline
spécificateur. L’utilisation inline
dans la définition de la fonction fait qu’il s’agit d’une fonction inline. Toutefois, vous ne pouvez pas redéfinir une fonction comme inline
après un appel à cette fonction.
inline
, __inline
et __forceinline
Les inline
spécificateurs et __inline
indiquent au compilateur d’insérer une copie du corps de la fonction à chaque emplacement où la fonction est appelée.
L’insertion, appelée extension inline ou inline, se produit uniquement si l’analyse coûts-avantages du compilateur montre qu’elle en vaut la peine. L’extension inline réduit la surcharge d’appel de fonction au coût potentiel d’une plus grande taille de code.
Le __forceinline
mot clé remplace l’analyse coûts-avantages et s’appuie plutôt sur le jugement du programmeur. Soyez prudent lors de l’utilisation de __forceinline
. L’utilisation indiscriminée de __forceinline
peut entraîner un code plus volumineux avec seulement des gains de performances marginaux ou, dans certains cas, des pertes de performances (en raison de la pagination accrue d’un fichier exécutable plus volumineux, par exemple).
Le compilateur traite les options d'expansion inline et les mots clés comme des suggestions. Il n’y a aucune garantie que les fonctions seront incorporées. Vous ne pouvez pas forcer le compilateur à inliner une fonction particulière, même avec le __forceinline
mot clé. Lorsque vous compilez avec /clr
, le compilateur n’intègre pas une fonction si des attributs de sécurité sont appliqués à la fonction.
Pour la compatibilité avec les versions précédentes, _inline
et _forceinline
sont synonymes respectivement de __inline
et __forceinline
, sauf si l’option du compilateur /Za (Désactiver les extensions de langage) est spécifiée.
Le inline
mot clé indique au compilateur que l’extension inline est préférable. Toutefois, le compilateur peut créer une instance séparée de la fonction (instanciation) et créer des liaisons d'appel standard au lieu d'insérer le code inline. Deux cas dans lesquels ce comportement peut se produire sont :
Fonctions récursives.
Fonctions référencées par l'intermédiaire d'un pointeur ailleurs dans l'unité de traduction.
Ces motifs peuvent interférer avec l’inline, comme d’autres, à la discrétion du compilateur; vous ne devez pas dépendre du inline
spécificateur pour provoquer l’inline d’une fonction.
Au lieu de développer une fonction inline définie dans un fichier d’en-tête, le compilateur peut la créer en tant que fonction pouvant être appelée dans plusieurs unités de traduction. Le compilateur marque la fonction générée pour l’éditeur de liens afin d’empêcher les violations d’une règle de définition (ODR).
Comme pour les fonctions normales, il n’existe aucun ordre défini pour l’évaluation des arguments dans une fonction inline. En fait, il peut être différent de l’ordre d’évaluation de l’argument lorsqu’il est passé à l’aide du protocole d’appel de fonction normal.
L’option /Ob d’optimisation du compilateur permet de déterminer si l’expansion de la fonction inline se produit réellement.
/LTCG inline plusieurs modules, qu’il soit demandé dans le code source ou non.
Exemple 1
// inline_keyword1.cpp// compile with: /cinline int max( int a , int b ) { if( a > b ) return a; return b;}
Les fonctions membres d’une classe peuvent être déclarées inline, soit à l’aide de la inline
mot clé, soit en plaçant la définition de fonction dans la définition de classe.
Exemple 2
// inline_keyword2.cpp// compile with: /EHsc /c#include <iostream>using namespace std;class MyClass {public: void print() { cout << i << ' '; } // Implicitly inlineprivate: int i;};
Spécifique à Microsoft
Le __inline
mot clé équivaut à inline
.
Même avec __forceinline
, le compilateur ne peut pas inline code dans toutes les circonstances. Le compilateur ne peut pas inliner une fonction si :
La fonction ou son appelant est compilé avec
/Ob0
(option par défaut pour les builds de débogage).La fonction et l'appelant utilisent différents types de gestion des exceptions (gestion des exceptionsC++ dans l'un, gestion structurée des exceptions dans l'autre).
La fonction a une liste d'arguments variable.
La fonction utilise un assembly inline, sauf si elle est compilée avec
/Ox
,/O1
ou/O2
.La fonction est récursive et n’a
#pragma inline_recursion(on)
pas défini. Avec le pragma, les fonctions récursives sont incorporées à une profondeur par défaut de 16appels. Pour réduire la profondeur de l’inlining, utilisez inline_depth pragma.La fonction est virtuelle et est appelée virtuellement. Les appels directs aux fonctions virtuelles peuvent être incorporés.
Le programme prend l'adresse de la fonction et l'appel est effectué via le pointeur vers la fonction. Les appels directs aux fonctions dont l'adresse est acceptée peuvent être incorporés.
La fonction est également marquée avec le naked__declspec modificateur.
Si le compilateur ne peut pas inline une fonction déclarée avec __forceinline
, il génère un avertissement de niveau 1, sauf dans les cas suivants :
La fonction est compilée à l’aide de /Od ou /Ob0. Aucune inlining n’est attendue dans ces cas.
La fonction est définie en externe, dans une bibliothèque incluse ou une autre unité de traduction, ou est une cible d’appel virtuel ou une cible d’appel indirect. Le compilateur ne peut pas identifier le code non incorporé qu’il ne trouve pas dans l’unité de traduction actuelle.
Les fonctions récursives peuvent être remplacées par du code inline à une profondeur spécifiée par le inline_depth pragma, jusqu’à un maximum de 16 appels. Au-delà de cette profondeur, les appels de fonction récursive sont traités comme des appels à une instance de la fonction. La profondeur à laquelle les fonctions récursives sont examinées par l’heuristique inline ne peut pas dépasser 16. Le inline_recursion pragma contrôle l’expansion inline d’une fonction actuellement en cours d’expansion. Pour obtenir des informations connexes, consultez l’option du compilateur Extension de fonction inline (/Ob).
FIN de la section spécifique à Microsoft
Pour plus d’informations sur l’utilisation du inline
spécificateur, consultez :
Fonctions membres des classes inline
Définition de fonctions C++ inline avec dllexport et dllimport
Quand utiliser les fonctions inline
Les fonctions inline sont utilisées de façon optimale pour les petites fonctions telles que l'accès aux membres de données privées. L’objectif main de ces fonctions « accesseur » à une ou deux lignes est de retourner des informations d’état sur les objets. Les fonctions courtes sont sensibles à la surcharge des appels de fonction. Les fonctions plus longues passent proportionnellement moins de temps dans la séquence d’appel et de retour et bénéficient moins de l’inlining.
Une Point
classe peut être définie comme suit :
// when_to_use_inline_functions.cppclass Point{public: // Define "accessor" functions as // reference types. unsigned& x(); unsigned& y();private: unsigned _x; unsigned _y;};inline unsigned& Point::x(){ return _x;}inline unsigned& Point::y(){ return _y;}int main(){}
En supposant que la manipulation de coordonnées est une opération relativement courante dans un client d’une telle classe, la spécification des deux fonctions d’accesseur (x
et y
dans l’exemple précédent) comme inline
permet généralement d’économiser la surcharge sur :
Appels de fonction (notamment le paramètre passe et place l'adresse de l'objet dans la pile)
Conservation du frame de pile de l'appelant
Nouvelle configuration du cadre de pile
Communication de la valeur de retour
Restauration de l’ancien cadre de pile
Renvoie
Fonctions inline et macros
Les fonctions inline sont similaires aux macros, car le code de fonction est développé au point de l’appel au moment de la compilation. Toutefois, les fonctions inline sont analysées par le compilateur et les macros sont développées par le préprocesseur. Par conséquent, il existe plusieurs différences importantes:
Les fonctions inline suivent tous les protocoles de sécurité de type appliqués sur les fonctions normales.
Les fonctions inline sont spécifiées à l’aide de la même syntaxe que toute autre fonction, sauf qu’elles incluent le
inline
mot clé dans la déclaration de fonction.Les expressions passées comme arguments aux fonctions inline sont évaluées une fois. Dans certains cas, les expressions passées comme arguments aux macros peuvent être évaluées plusieurs fois.
L'exemple suivant montre une macro qui convertit les minuscules en majuscules:
// inline_functions_macro.c#include <stdio.h>#include <conio.h>#define toupper(a) ((a) >= 'a' && ((a) <= 'z') ? ((a)-('a'-'A')):(a))int main() { char ch; printf_s("Enter a character: "); ch = toupper( getc(stdin) ); printf_s( "%c", ch );}// Sample Input: xyz// Sample Output: Z
L’objectif de l’expression toupper(getc(stdin))
est qu’un caractère doit être lu à partir de l’appareil console (stdin
) et, si nécessaire, converti en majuscules.
En raison de l’implémentation de la macro, getc
est exécuté une fois pour déterminer si le caractère est supérieur ou égal à « a », et une fois pour déterminer s’il est inférieur ou égal à « z ». S’il se trouve dans cette plage, getc
est réexécuté pour convertir le caractère en majuscules. Cela signifie que le programme attend deux ou trois caractères quand, dans l’idéal, il ne devrait attendre qu’un seul.
Les fonctions inline remédient au problème décritauparavant:
// inline_functions_inline.cpp#include <stdio.h>#include <conio.h>inline char toupper( char a ) { return ((a >= 'a' && a <= 'z') ? a-('a'-'A') : a );}int main() { printf_s("Enter a character: "); char ch = toupper( getc(stdin) ); printf_s( "%c", ch );}
Sample Input: aSample Output: A
Voir aussi
noinline
auto_inline