FAQ C++Consultez toutes les FAQ

Nombre d'auteurs : 35, nombre de questions : 368, dernière mise à jour : 23 mai 2017  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de http://www.developpez.com et de l'expérience personnelle des auteurs.

Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur ou si vous souhaitez devenir rédacteur, lisez ceci.

Sur ce, nous vous souhaitons une bonne lecture.


SommaireLes fonctionsLes fonctions inline (8)
précédent sommaire suivant
 

Quand le compilateur évalue l'appel d'une fonction inline, le code complet de cette fonction est inséré dans le code de l'appelant (c'est le même principe que ce qui se passe avec un #define). Cela peut, parmi beaucoup d'autres choses, améliorer les performances, étant donné que l'optimiseur peut intégrer directement le code appelé, voire optimiser le code appelé en fonction du code appelant.

Il y a plusieurs façons d'indiquer qu'une fonction est inline, certaines impliquant le mot-clé inline, d'autres non. Peu importe comment une fonction est déclarée inline, c'est une demande que le compilateur est autorisé à ignorer : il peut en évaluer certaines, toutes ou même aucune. (Ne soyez pas découragés si cela semble désespérément vague. La flexibilité de ce qui précède est un avantage important : le compilateur peut gérer de grosses fonctions différemment des petites, de plus, cela permet au compilateur de générer du code facile à déboguer si vous spécifiez les bonnes options de compilation.)

Mis à jour le 5 mars 2004 Cline

Supposons l'appel suivant à une fonction g() :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
void f() 
 { 
   int x = /*...*/; 
   int y = /*...*/; 
   int z = /*...*/; 
   // ...code qui utilise x, y et z... 
   g(x, y, z); 
   // ...plus de code qui utilise x, y et z... 
 }
En supposant que l'on ait une implémentation typique de C++, possédant des registres et une pile, les registres et les paramètres sont déposés sur la pile juste avant l'appel de g(). Les paramètres sont ensuite retirés de la pile lors de l'entrée dans g(), redéposés lors de la sortie de g() et finalement relus dans f(). Cela fait un certain nombre de lectures et écritures inutiles, spécialement dans le cas ou le compilateur a la possibilité d'utiliser les registres pour les variables x, y et z : chaque variable pourrait être écrite deux fois (en tant que registre et en tant que paramètre) et lue deux fois aussi (lors de son utilisation dans g() et pour restaurer les registres au retour dans f()).

Code c++ : Sélectionner tout
1
2
3
4
void g(int x, int y, int z) 
 { 
   // ...code qui utilise x, y et z... 
 }
Si le compilateur évalue l'appel de g() en tant qu'inline, toutes ces lectures et écritures disparaissent. Les registres n'auront pas besoin d'être écrits deux fois et les paramètres n'auront pas besoin d'être empilés ni désempilés, étant donné que l'optimiseur saura qu'ils sont déjà dans les registres.

Bien entendu, votre configuration particulière sera différente, et il existe de nombreux cas qui sont en dehors du cas de figure présenté ici, mais l'exemple ci-dessus sert à illustrer ce qui peut se passer lors de l'intégration inline.

Mis à jour le 5 mars 2004 Cline

Cela dépend.

Il n'y a pas de réponse simple. Les fonctions inline peuvent rendre le code plus rapide, mais elles peuvent aussi le rendre plus lent. Elles peuvent rendre le code plus gros ou le rendre plus petit. Elles peuvent ralentir considérablement le programme ou le rendre plus performant. Elles peuvent aussi n'avoir aucun impact sur la rapidité du code.

Les fonctions inline peuvent rendre le code plus rapide Comme vu précédemment, l'intégration du code peut supprimer une poignée d'instructions inutiles, ce qui peut rendre le code plus rapide.

Les fonctions inline peuvent rendre le code plus lent Un excès de fonctions inline peur rendre le code 'indigeste', ce qui peut provoquer un excès d'accès à la mémoire virtuelle sur certains systèmes. En d'autres mots, si la taille de l'exécutable est trop importante, le système risque de passer beaucoup de temps à faire de la pagination sur disque pour accéder à la suite du code.

Les fonctions inline peuvent rendre le code plus gros C'est la notion de code 'indigeste', décrite ci-dessus. Par exemple, si un programme a 100 fonctions inline qui augmenteront à chaque fois la taille de l'exécutable de 100 bytes et qui sont appelées 100 fois chacune, l'augmentation de taille de l'exécutable sera proche de 1 MB. Est-ce que ce Mo posera problème ? Qui sait, mais ce Mo risque d'être celui qui fera faire de la pagination au système et donc le ralentir.

Les fonctions inline peuvent rendre le code plus petit Les compilateurs génèrent souvent plus de code pour empiler / désempiler les paramètres que l'inclusion du code ne le ferait. C'est ce qui arrive avec de très petites fonctions, et cela peut même arriver avec de grosses fonctions quand l'optimiseur arrive à supprimer le code redondant via l'inclusion du code - l'optimiseur peut donc transformer de grosses fonctions en petites.

Les fonctions inline peuvent augmenter la pagination Le code généré peut devenir très gros, ce qui risque de causer un ralentissement considérable.

Les fonctions inline peuvent réduire la pagination Le nombre de pages qui doivent se trouver en mémoire au même moment peut se réduire, alors que la taille de l'exécutable augmente. Quand f() appelle g(), le code peut très bien se trouver dans deux pages différentes, alors que lorsque le compilateur inclut le code de g() dans f(), le code a plus de probabilité de se trouver dans la même page.

Les fonctions inline peuvent n'avoir aucune influence sur les performances Les performances ne sont pas liées qu'au CPU. Par contre, les entrées/sorties, les accès aux bases de données, l'accès au réseau peuvent représenter un sérieux goulot d'étranglement. À moins que votre CPU ne soit utilisé à 100 % la plupart du temps, l'utilisation des fonctions inline n'améliorera pas les performances générales du système (et même si le goulot d'étranglement se situe au niveau du CPU, les fonctions inline ne seront utiles que dans le code posant problème, ce qui représente souvent de très petits morceaux de code).

Il n'y a pas de réponse simple : vous devez essayer et voir ce qui est le mieux. Ne vous limitez pas à des réponses simplistes telles que « Ne jamais utiliser les fonctions inline » ou « Toujours utiliser les fonctions inline » ou « N'utiliser les fonctions inline que si le code fait moins de . lignes de code ». Ces règles arbitraires sont peut-être faciles à écrire, mais les résultats sont plus que décevants.

Mis à jour le 5 mars 2004 Cline

En C pur, vous pouvez réaliser des « structs (structures) encapsulées » en mettant un void * dans un struct, où le void * pointe sur les vraies données qui sont inconnues aux utilisateurs du struct. Ainsi ces même utilisateurs du struct ne peuvent pas interpréter les données pointées par void *, mais les fonctions d'accès peuvent elles convertir du void * vers le type de données caché. Ce qui donne une forme de l'encapsulation.

Malheureusement ceci impose de renoncer à la sûreté de type, et impose également un appel de fonction pour accéder même aux zones insignifiantes de la structure (si vous permettiez l'accès direct au champs de la structure, chacun pourrait accéder directement à toute la structure puisqu'il connaîtrait nécessairement les données pointées par void *, et il deviendrait difficile de changer la structure de données sous-jacente).

Le temps d'appel de fonction est court, mais il s'ajoute à chaque appel. Les classes C++ permettent à ces appels de fonction d'être insérés inline. Ceci vous laisse la sûreté de l'encapsulation avec en plus la vitesse des accès directs. En outre, les types des paramètres de ces fonctions inline sont contrôlés par le compilateur, ce qui est une amélioration par rapport aux macros #define du C.

Mis à jour le 5 mars 2004 Cline

Parce que les #define sont mauvais. Mais parfois il faut les utiliser.

Contrairement aux #define, les fonctions inline évitent des erreurs très difficiles à tracer, étant donné que les fonctions inline évaluent toujours chaque argument une et une seule fois. En d'autres mots, l'invocation d'une fonction inline est sémantiquement identique à l'invocation d'une fonction classique, avec la seule différence de la rapidité.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Macro qui renvoie la valeur absolue de i 
#define unsafe(i)  \ 
         ( (i) >= 0 ? (i) : -(i) ) 
  
// Fonction inline qui renvoie la valeur absolue de i 
inline 
int safe(int i) 
{ 
    return i >= 0 ? i : -i; 
} 
  
int f(); 
  
void userCode(int x) 
{ 
    int ans; 
  
    ans = unsafe(x++);   // Erreur ! x est incrémenté deux fois 
    ans = unsafe(f());   // Danger ! f() est appelé deux fois 
  
    ans = safe(x++);     // Correct ! x est incrémenté une seule fois 
    ans = safe(f());     // Correct ! f() est appelé une seule fois 
}
Une autre différence est que les types des paramètres sont vérifiés, et les conversions nécessaires effectuées.

Les macros sont à proscrire, ne les utilisez que si vous n'avez pas d'autre alternative.

Mis à jour le 5 mars 2004 Cline

Quand vous déclarez une fonction inline, elle a exactement l'aspect d'une fonction normale :

Code c++ : Sélectionner tout
void f(int i, char c);
Mais quand vous définissez une fonction inline, vous ajoutez au début de la définition de la fonction le mot-clé inline, et vous mettez la définition dans le fichier d'en-tête :

Code c++ : Sélectionner tout
1
2
3
4
inline void f(int i, char c) 
{ 
    // ... 
}

Mis à jour le 5 mars 2004 Cline

Quand vous déclarez inline une fonction membre, elle a exactement l'aspect d'une fonction membre normale :

Code c++ : Sélectionner tout
1
2
3
4
class Fred { 
    public: 
        void f(int i, char c); 
};
Mais quand vous définissez une fonction membre inline, vous ajoutez au début de la définition de la fonction membre le mot-clé inline, et vous mettez la définition dans un fichier d'en-tête :

Code c++ : Sélectionner tout
1
2
3
4
inline void Fred::f(int i, char c) 
{ 
    // ... 
}
Il est habituellement impératif que la définition de la fonction (la partie entre { ... }) soit placée dans un fichier d'en-tête.
Si vous mettiez inline la définition d'une fonction dans un fichier d'implémentation cpp, et si cette fonction était appelée d'un autre fichier cpp, vous obtiendriez "une erreur externe" (fonction non définie) au moment de l'édition de liens.

Mis à jour le 5 mars 2004 Cline

Oui : définissez la fonction de membre dans le corps de classe elle-même :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
class Fred 
{ 
public: 
    void f(int i, char c) 
    { 
        // ... 
    } 
};
Bien que ce soit plus facile pour la personne qui écrit la classe, c'est aussi plus dur pour le lecteur puisqu'on mélange « ce que fait » la classe avec « comment elle le fait ». En raison de ce mélange, on préfère normalement définir des fonctions membres en dehors du corps de classe avec le mot-clé inline. Comprenez que dans un monde orienté objet et réutilisation, il y a beaucoup de gens qui utilisent la classe, mais une seule personne qui la crée (vous même). C'est pourquoi vous devriez faire les choses en faveur du plus grand nombre plutôt que pour le plus petit.

Mis à jour le 5 mars 2004 Cline

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2017 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

 
Contacter le responsable de la rubrique C++