Quand dois-je écrire le mot-clé ‘inline’ pour une fonction / méthode?

Quand dois-je écrire le mot clé en inline pour une fonction / méthode en C ++?

Après avoir vu des réponses, quelques questions connexes:

Oh mec, une de mes bêtes noires.

inline ressemble plus à static ou extern qu’à une directive indiquant au compilateur d’inclure vos fonctions. extern , static , inline sont des directives de liaison, utilisées presque exclusivement par l’éditeur de liens, et non par le compilateur.

On dit que inline indications en inline pour le compilateur que vous pensez que la fonction devrait être en ligne. C’était peut-être vrai en 1998, mais une décennie plus tard, le compilateur n’a plus besoin de tels indices. Sans compter que les humains ont généralement tort quand il s’agit d’optimiser le code, la plupart des compilateurs ignorent l’indice.

  • static – le nom de la variable / fonction ne peut pas être utilisé dans d’autres unités de traduction. Linker doit s’assurer qu’il n’utilise pas accidentellement une variable / fonction définie statiquement à partir d’une autre unité de traduction.

  • extern – utilisez ce nom de variable / fonction dans cette unité de traduction mais ne vous plaignez pas si elle n’est pas définie. L’éditeur de liens le sortingera 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.

Note: Généralement, déclarer des modèles en inline est inutile, car ils ont déjà la sémantique de liaison en inline . Cependant, explicit spécialisation explicit et l’instanciation des modèles nécessitent d’être utilisés en ligne.


Réponses spécifiques à vos questions:

  • Quand dois-je écrire le mot-clé ‘inline’ pour une fonction / méthode en C ++?

    Seulement lorsque vous souhaitez que la fonction soit définie dans un en-tête. Plus exactement 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 des fonctions de petite taille (comme dans une ligne) dans le fichier d’en-tête, car cela donne au compilateur plus d’informations pour travailler tout en optimisant votre code. Cela augmente également le temps de compilation.

  • Quand ne devrais-je pas écrire le mot-clé ‘inline’ pour une fonction / méthode en C ++?

    N’ajoutez pas de ligne juste parce que vous pensez que votre code s’exécutera plus rapidement si le compilateur l’a intégré.

  • Quand le compilateur ne saura-t-il pas quand faire une fonction / méthode “inline”?

    Généralement, le compilateur sera en mesure de le faire mieux que vous. Cependant, le compilateur n’a pas la possibilité d’insérer du code s’il ne possède pas la définition de la fonction. Dans le code optimisé au maximum, toutes private méthodes private sont généralement intégrées, que vous le demandiez ou non.

    En guise de réserve pour empêcher l’inclusion dans GCC, utilisez __atsortingbute__(( noinline )) , et dans Visual Studio, utilisez __declspec(noinline) .

  • Est-ce important qu’une application soit multithreadée quand on écrit “inline” pour une fonction / méthode?

    Le multithreading n’affecte en rien l’inline.

Je voudrais consortingbuer à toutes les bonnes réponses dans ce fil avec un exemple convaincant pour disperser tout malentendu restant.

Étant donné deux fichiers source, tels que:

  • inline111.cpp:

     #include  void bar(); inline int fun() { return 111; } int main() { std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun; bar(); } 
  • inline222.cpp:

     #include  inline int fun() { return 222; } void bar() { std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun; } 

  • Cas A:

    Comstackr :

     g++ -std=c++11 inline111.cpp inline222.cpp 

    Sortie :

     inline111: fun() = 111, &fun = 0x4029a0 inline222: fun() = 111, &fun = 0x4029a0 

    Discussion :

    1. Même si vous devez avoir des définitions identiques de vos fonctions en ligne, le compilateur C ++ ne le signale pas si ce n'est pas le cas (en fait, en raison d' une compilation séparée, il n'a aucun moyen de le vérifier). C'est votre devoir de vous en assurer!

    2. Linker ne se plaint pas de la règle de définition , car fun() est déclaré en inline . Cependant, comme inline111.cpp est la première unité de traduction (qui appelle en fait fun() ) traitée par le compilateur, le compilateur instancie fun() lors de son premier appel dans inline111.cpp . Si le compilateur décide de ne pas étendre fun() lors de son appel de n’importe où dans votre programme ( par exemple depuis inline222.cpp ), l’appel de fun() sera toujours lié à son instance produite par inline111.cpp (appel à fun() dans inline222.cpp peut également produire une instance dans cette unité de traduction, mais elle restra non liée). En effet, cela ressort clairement des impressions identiques &fun = 0x4029a0 .

    3. Enfin, en dépit de la suggestion en inline au compilateur d’ étendre le fun() un trait fun() , il ignore complètement votre suggestion, ce qui est clair car fun() = 111 dans les deux lignes.


  • Cas B:

    Comstackr (avis ordre inverse) :

     g++ -std=c++11 inline222.cpp inline111.cpp 

    Sortie :

     inline111: fun() = 222, &fun = 0x402980 inline222: fun() = 222, &fun = 0x402980 

    Discussion :

    1. Ce cas affirme ce qui a été discuté dans le cas A.

    2. Notez un point important, à savoir que si vous commentez l'appel réel à fun() dans inline222.cpp ( par exemple, commentez complètement l'instruction cout in dans inline222.cpp ), malgré l'ordre de compilation de vos unités de traduction, fun() sera instancié lors de sa première rencontre d'appel dans inline111.cpp , résultant en une impression pour le cas B comme inline111: fun() = 111, &fun = 0x402980 .


  • Cas C:

    Comstackr (remarque -O2) :

     g++ -std=c++11 -O2 inline222.cpp inline111.cpp 

    ou

     g++ -std=c++11 -O2 inline111.cpp inline222.cpp 

    Sortie :

     inline111: fun() = 111, &fun = 0x402900 inline222: fun() = 222, &fun = 0x402900 

    Discussion :

    1. Comme cela est décrit ici , l'optimisation -O2 encourage le compilateur à développer les fonctions qui peuvent être intégrées (notez également que -fno-inline est -fno-inline par défaut sans options d'optimisation). Comme le montre l’impression ici, le fun() a été développé en ligne (conformément à sa définition dans cette unité de traduction particulière ), ce qui entraîne deux impressions fun() différentes . Malgré cela, il n'y a toujours qu'une seule instance de fun() requirejse par la norme, comme le montre une impression identique &fun .

Vous devez toujours incorporer explicitement votre fonction lorsque vous faites une spécialisation de modèle (si la spécialisation se trouve dans le fichier .h)

1) De nos jours, à peu près jamais. Si c’est une bonne idée d’intégrer une fonction, le compilateur le fera sans votre aide.

2) toujours Voir # 1.

(Édité pour refléter que vous avez divisé votre question en deux questions …)

Quand ne devrais-je pas écrire le mot-clé ‘inline’ pour une fonction / méthode en C ++?

Si la fonction est définie dans le fichier .cpp , vous ne devez pas écrire le mot clé.

Quand le compilateur ne saura-t-il pas quand faire une fonction / méthode “inline”?

Il n’y a pas une telle situation. Le compilateur ne peut pas créer une fonction en ligne. Tout ce qu’il peut faire est d’inclure certains ou tous les 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 est capable de le faire).

Est-ce important qu’une application soit multithreadée quand on écrit “inline” pour une fonction / méthode?

Non, ça ne fait rien du tout.

En réalité, à peu près jamais. Tout ce que vous faites est de suggérer que le compilateur insère une fonction donnée (par exemple, remplacer tous les appels à cette fonction / w son corps). Bien sûr, il n’y a aucune garantie: le compilateur peut ignorer la directive.

Le compilateur fera généralement un bon travail de détection et d’optimisation.

  • Quand le compilateur ne saura-t-il pas quand faire une fonction / méthode “inline”?

Cela dépend du compilateur utilisé. Ne croyez pas aveuglément qu’aujourd’hui, les compilateurs savent mieux que les humains comment s’y intégrer et que 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 sois d’accord sur le fait que sur le plan idéologique ces arguments sont corrects, il peut être différent de rencontrer la réalité.

Après avoir lu plusieurs discussions autour de moi, j’ai essayé par curiosité les effets de l’inline sur le code que je travaille et les résultats ont été que j’ai eu un 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); ajout en ligne aux points critiques accélérés 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 exigeantes en CPU et que vous savez exactement quel est le goulot d’étranglement.

gcc par défaut n’intègre aucune fonction lors de la compilation sans optimisation activée. Je ne connais pas le studio visuel – deft_code

J’ai vérifié cela pour Visual Studio 9 (15.00.30729.01) en compilant avec / FAcs et en regardant le code de l’assembly: Le compilateur produisait des appels aux fonctions membres sans que l’optimisation soit 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é.

Vous voulez le mettre au tout début, avant le type de retour. Mais la plupart des compilateurs l’ignorent. Si elle est définie et que son bloc de code est plus petit, la plupart des compilateurs le considèrent de toute façon comme étant en ligne.

Lors du développement et du débogage du code, laissez inline sortie. Cela complique le débogage.

La principale raison de les append est d’aider à optimiser le code généré. En règle générale, cet échange augmente l’espace de code pour la vitesse, mais parfois en inline enregistre à la fois l’espace de code et le temps d’exécution.

L’augmentation prématurée de ce type de reflection sur l’optimisation des performances avant la fin de l’algorithme.

Quand on devrait aligner:

1.Lorsqu’on veut éviter que des événements surviennent lorsque la fonction est appelée, comme le passage de parameters, le transfert de contrôle, le retour de contrôle, etc.

2. La fonction doit être petite, fréquemment appelée et la création de lignes en ligne est vraiment avantageuse, car selon la règle 80-20, essayez de les aligner, ce qui aura un impact majeur sur les performances du programme.

Comme nous le soaps, l’inline n’est qu’une requête similaire au compilateur pour s’enregistrer et cela vous coûtera à la taille du code object.

À moins que vous n’écriviez une bibliothèque ou que vous ayez des raisons spéciales, vous pouvez oublier l’utilisation de l’ inline et utiliser plutôt l’ optimisation du temps de liaison . Cela supprime la nécessité pour une définition de fonction de figurer dans un en-tête pour pouvoir être intégrée aux unités de compilation, ce qui est précisément ce que permet l’ inline .

(Mais voir Y a – t-il une raison pour ne pas utiliser l’optimisation du temps de liaison? )