Définition de la fonction d’écriture dans les fichiers d’en-tête en C ++

J’ai une classe qui a beaucoup de petites fonctions. Par petites fonctions, j’entends les fonctions qui ne font aucun traitement mais renvoient simplement une valeur littérale. Quelque chose comme:

ssortingng Foo::method() const{ return "A"; } 

J’ai créé un fichier d’entête “Foo.h” et le fichier source “Foo.cpp”. Mais comme la fonction est très petite, je pense à la mettre dans le fichier d’en-tête lui-même. J’ai les questions suivantes:

  1. Existe-t-il des performances ou d’autres problèmes si je mets ces définitions de fonctions dans le fichier d’en-tête? Je vais avoir beaucoup de fonctions comme ça.
  2. À ma connaissance, lorsque la compilation est terminée, le compilateur va développer le fichier d’en-tête et le placer là où il est inclus. Est-ce exact?

Si la fonction est petite (la probabilité de la changer souvent est faible) et si la fonction peut être placée dans l’en-tête sans inclure des myriades d’autres en-têtes (parce que votre fonction en dépend), cela est parfaitement valable. Si vous les déclarez extern inline, le compilateur doit lui donner la même adresse pour chaque unité de compilation:

headera.h :

 inline ssortingng method() { return something; } 

Les fonctions membres sont implicites en ligne à condition qu’elles soient définies dans leur classe. La même chose est vraie pour eux true: S’ils peuvent être mis dans l’en-tête sans tracas, vous pouvez effectivement le faire.

Étant donné que le code de la fonction est placé dans l’en-tête et visible, le compilateur est capable de les appeler en ligne, c’est-à-dire de placer le code de la fonction directement sur le site d’appel. parce que le compilateur décide de cette manière, cependant: mettre uniquement en ligne est un indice pour le compilateur à ce sujet). Cela peut entraîner une amélioration des performances, car le compilateur voit maintenant où les arguments correspondent aux variables locales de la fonction et où l’argument ne se alias pas – et enfin, l’allocation des frameworks de fonctions n’est plus nécessaire.

À ma connaissance, lorsque la compilation est terminée, le compilateur va développer le fichier d’en-tête et le placer là où il est inclus. Est-ce exact?

Oui c’est correct. La fonction sera définie à chaque endroit où vous incluez son en-tête. Le compilateur se souciera de ne placer qu’une seule instance dans le programme résultant, en éliminant les autres.

Selon votre compilateur et ses parameters, il peut effectuer l’une des opérations suivantes:

  • Il peut ignorer le mot-clé inline (il ne s’agit que d’un indice pour le compilateur, pas d’une commande) et générer des fonctions autonomes. Il peut le faire si vos fonctions dépassent un seuil de complexité dépendant du compilateur. par exemple trop de boucles nestedes.
  • Cela peut décider que votre fonction autonome est un bon candidat pour l’expansion en ligne.

Dans de nombreux cas, le compilateur est beaucoup mieux placé pour déterminer si une fonction doit être en ligne que vous ne l’avez fait, il est donc inutile de la deviner. J’aime utiliser l’implémentation implicite lorsqu’une classe possède de nombreuses petites fonctions uniquement parce que l’implémentation est pratique dans la classe. Cela ne fonctionne pas si bien pour les grandes fonctions.

L’autre chose à garder à l’esprit est que si vous exportez une classe dans une DLL / bibliothèque partagée (ce n’est pas une bonne idée à mon humble avis, mais les gens le font quand même), vous devez faire très attention aux fonctions en ligne. Si le compilateur qui a construit la DLL décide qu’une fonction doit être insérée, vous avez quelques problèmes potentiels:

  1. Le compilateur qui crée le programme à l’aide de la DLL peut décider de ne pas incorporer la fonction afin de générer une référence de symbole à une fonction qui n’existe pas et la DLL ne se chargera pas.
  2. Si vous mettez à jour la DLL et modifiez la fonction intégrée, le programme client utilisera toujours l’ancienne version de cette fonction car la fonction est intégrée au code client.

Il y aura une augmentation des performances car l’implémentation dans les fichiers d’en-tête est implicitement intégrée. Comme vous l’avez mentionné, vos fonctions sont réduites, les opérations en ligne vous seront très utiles.

Ce que vous dites à propos du compilateur est également vrai. Il n’y a pas de différence pour le compilateur – autre que l’inline – entre le code dans le fichier d’en-tête ou le fichier .cpp .

  1. Si vos fonctions sont aussi simples, rendez-les en ligne et vous devrez les coller dans le fichier d’en-tête. En dehors de cela, toutes les conventions ne sont que cela – des conventions.

  2. Oui, le compilateur développe le fichier d’en-tête où il rencontre les instructions #include.

Cela dépend des normes de codage applicables dans votre cas, mais:

Les petites fonctions sans boucles et tout le rest devraient être intégrées pour obtenir de meilleures performances (mais un code légèrement plus volumineux – important pour certaines applications limitées ou intégrées).

Si vous avez le corps de la fonction dans l’en-tête, vous l’aurez par défaut en ligne (d) (ce qui est une bonne chose en matière de vitesse).

Avant la création du fichier object par le compilateur, le préprocesseur est appelé (option -E pour gcc) et le résultat est envoyé au compilateur qui crée l’object en dehors du code.

Donc, la réponse la plus courte est la suivante:

– Déclarer des fonctions dans l’en-tête est bon pour la vitesse (mais pas pour l’espace) –

Vous devez utiliser des fonctions en ligne. Lisez ces fonctions en ligne pour une meilleure compréhension et les compromis impliqués.

C ++ ne se plaindra pas si vous le faites, mais en général, vous ne devriez pas.

Lorsque vous incluez un fichier, tout le contenu du fichier inclus est inséré au point d’inclusion. Cela signifie que toutes les définitions que vous mettez dans votre en-tête sont copiées dans chaque fichier qui inclut cet en-tête.

Pour les petits projets, cela ne devrait pas poser beaucoup de problèmes. Mais pour les projets plus importants, cela peut prendre beaucoup plus de temps à comstackr (car le même code est recompilé à chaque fois qu’il est rencontré) et peut considérablement gonfler la taille de votre exécutable. Si vous modifiez une définition dans un fichier de code, seul ce fichier .cpp doit être recompilé. Si vous modifiez une définition dans un fichier d’en-tête, chaque fichier de code incluant l’en-tête doit être recompilé. Un petit changement peut vous obliger à recomstackr tout votre projet!

Parfois, des exceptions sont faites pour les fonctions sortingviales qui sont peu susceptibles de changer (par exemple, lorsque la définition de la fonction est une ligne).