Fonctions inline (C++) (2023)

  • 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 GetBalancemembres , Depositet 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, /O1ou /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

Top Articles
Latest Posts
Article information

Author: Pres. Lawanda Wiegand

Last Updated: 03/10/2023

Views: 6272

Rating: 4 / 5 (51 voted)

Reviews: 82% of readers found this page helpful

Author information

Name: Pres. Lawanda Wiegand

Birthday: 1993-01-10

Address: Suite 391 6963 Ullrich Shore, Bellefort, WI 01350-7893

Phone: +6806610432415

Job: Dynamic Manufacturing Assistant

Hobby: amateur radio, Taekwondo, Wood carving, Parkour, Skateboarding, Running, Rafting

Introduction: My name is Pres. Lawanda Wiegand, I am a inquisitive, helpful, glamorous, cheerful, open, clever, innocent person who loves writing and wants to share my knowledge and understanding with you.