web-dev-qa-db-fra.com

Écriture d'une définition de fonction dans des fichiers d'en-tête en C ++

J'ai une classe qui a de nombreuses petites fonctions. Par petites fonctions, j'entends des fonctions qui ne font aucun traitement mais renvoient juste une valeur littérale. Quelque chose comme:

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

J'ai créé un fichier d'en-tête "Foo.h" et un 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 problèmes de performances ou autres si je mets ces définitions de fonction dans le fichier d'en-tête? J'aurai de nombreuses fonctions comme celle-ci.
  2. Ma compréhension est que lorsque la compilation est terminée, le compilateur développera le fichier d'en-tête et le placera là où il est inclus. Est-ce exact?
61
Navaneeth K N

Si la fonction est petite (la chance que vous la changiez 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 (car votre fonction en dépend), il est parfaitement valide de le faire. Si vous les déclarez extern en ligne, le compilateur doit lui donner la même adresse pour chaque unité de compilation:

headera.h:

inline string 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: s'ils peuvent être mis dans l'en-tête sans tracas, vous pouvez en effet le faire.

Parce que le code de la fonction est placé dans l'en-tête et visible, le compilateur est en mesure de les appeler en ligne, c'est-à-dire de mettre le code de la fonction directement sur le site de l'appel (pas tant parce que vous le mettez en ligne avant, mais plus parce que le compilateur décide de cette façon, cependant. La mise en ligne uniquement 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 à la fonction, et où les arguments ne s'aliasent pas - et enfin et surtout, l'allocation de trame de fonction n'est plus nécessaire.

Ma compréhension est que lorsque la compilation est terminée, le compilateur développera le fichier d'en-tête et le placera 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 d'en mettre une seule instance dans le programme résultant, en éliminant les autres.

67

Selon votre compilateur et ses paramètres, il peut effectuer l'une des opérations suivantes:

  • Il peut ignorer le mot clé inline (c'est juste un indice pour le compilateur, pas 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 imbriquées.
  • Il peut décider que votre fonction autonome est un bon candidat pour l'expansion en ligne.

Dans de nombreux cas, le compilateur est dans une bien meilleure position pour déterminer si une fonction doit être insérée que vous, il est donc inutile de la deviner. J'aime utiliser l'incrustation implicite lorsqu'une classe a de nombreuses petites fonctions uniquement parce qu'il est pratique d'avoir l'implémentation juste là dans la classe. Cela ne fonctionne pas si bien pour des fonctions plus importantes.

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 être très prudent avec les fonctions en ligne. Si le compilateur qui a construit le DLL décide qu'une fonction doit être insérée, vous avez quelques problèmes potentiels:

  1. Le compilateur qui construit le programme à l'aide de la DLL peut décider de ne pas aligner la fonction afin de générer une référence de symbole à une fonction qui n'existe pas et la DLL = ne se charge 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 depuis que la fonction a été intégrée dans le code client.
12
Ferruccio

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 petites, le fonctionnement en ligne vous sera si bénéfique à mon humble avis.

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 .cpp fichier.

4
Qubeuc
  1. Si vos fonctions sont aussi simples, rendez-les en ligne et vous devrez quand même 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.

2
sykora

Cela dépend des normes de codage qui s'appliquent dans votre cas mais:

Les petites fonctions sans boucles et rien d'autre devraient être intégrées pour de meilleures performances (mais un code légèrement plus grand - important pour certaines applications contraintes ou intégrées).

Si vous avez le corps de la fonction dans l'en-tête, vous l'aurez par défaut inline (d) (ce qui est une bonne chose en termes de vitesse).

Avant que le fichier objet soit créé par le compilateur, le préprocesseur est appelé (option -E pour gcc) et le résultat est envoyé au compilateur qui crée l'objet à partir du code.

La réponse la plus courte est donc:

- La déclaration de fonctions dans l'en-tête est bonne pour la vitesse (mais pas pour l'espace) -

2
INS

C++ ne se plaindra pas si vous le faites, mais en règle générale, 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, il est peu probable que cela pose problème. Mais pour les projets plus importants, cela peut prendre plus de temps à compiler (car le même code est recompilé à chaque fois qu'il est rencontré) et pourrait considérablement alourdir la taille de votre exécutable. Si vous apportez une modification à une définition dans un fichier de code, seul ce fichier .cpp doit être recompilé. Si vous apportez une modification à une définition dans un fichier d'en-tête, chaque fichier de code qui inclut l'en-tête doit être recompilé. Un petit changement peut vous obliger à recompiler tout votre projet!

Parfois, des exceptions sont faites pour les fonctions triviales qui ne changeront probablement pas (par exemple, lorsque la définition de la fonction est sur une ligne).

Source: http://archive.li/ACYlo (version précédente du chapitre 1.9 sur learncpp.com)

1
Pushpak Sharma

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

0
Naveen