Hypothèses
L'un des avantages des bibliothèques d'en-tête uniquement pour C ++ est qu'elles n'ont pas besoin d'être compilées séparément.
En C et C ++
inline
n'a de sens que si la fonction est définie dans un fichier d'en-tête *.Traditionnellement, en C, on utilisait la disposition .c / .h, où l'en-tête représente l'interface publique minimale de l'unité de traduction. De même, .cpp / hpp.
Question
Les bibliothèques comportant uniquement des en-têtes sont-elles généralement plus efficaces en termes de code et de temps d’exécution que la présentation classique? Si oui, est-ce dû à une optimisation en ligne étendue ou à d'autres optimisations?
* - la définition de la fonction dans un en-tête permet au compilateur de voir l'implémentation lors de la compilation de n'importe quelle unité de traduction et rend pratiquement possible le code en ligne
Réponses:
Non, ce n'est pas un avantage, bien au contraire - la partie principale de la bibliothèque doit être compilée aussi souvent qu'elle est incluse, pas une fois. Cela augmentera généralement les temps de compilation. Toutefois, si vous faites référence aux avantages énumérés ici dans Wikipedia : cet article parle de la réduction des coûts administratifs liés au processus de construction, d’emballage et de déploiement.
Cela dépend du système de compilation / édition de liens, mais je suppose que pour la plupart des compilateurs C et C ++ existants, cela est vrai.
C'est la plupart du temps correct. Les en-têtes de classe C ++ contiennent souvent plus que l'interface publique minimale - ils contiennent généralement aussi beaucoup de choses privées. Pour atténuer cela, des expressions telles que l' idiome PIMPL sont utilisées. C'est quelque chose qui ressemble à "l'opposé" d'une bibliothèque avec en-tête uniquement, elle essaie de minimiser le contenu d'en-tête nécessaire.
Mais pour répondre à votre question principale: c’est un compromis. Plus il y a de code de bibliothèque dans les fichiers d'en-tête, plus le compilateur a une chance d'optimiser sa rapidité (si cela se produit réellement, ou si l'augmentation est notable, la question est complètement différente). D'autre part, trop de code dans les en-têtes augmente le temps de compilation. En particulier dans les grands projets C ++, cela peut devenir un problème sérieux, voir "Conception de logiciels C ++ à grande échelle" de John Lakos - bien que le livre soit un peu obsolète et que certains des problèmes décrits ici soient traités par les compilateurs modernes, les idées générales / les solutions sont toujours valables.
En particulier, lorsque vous n'utilisez pas de bibliothèque stable (tierce partie), mais que vous développez vos propres bibliothèques au cours de votre projet, les temps de compilation deviennent apparents. Chaque fois que vous modifiez quelque chose dans la bibliothèque, vous devez modifier un fichier d'en-tête, ce qui entraînera une recompilation et une liaison de toutes les unités dépendantes.
IMHO la popularité des bibliothèques avec en-tête seulement est causée par la popularité de la méta-programmation. Pour la plupart des compilateurs, les bibliothèques basées sur un modèle doivent être en-tête uniquement car le compilateur ne peut démarrer le processus de compilation principal que lorsque les paramètres de type sont fournis, et pour une compilation et une optimisation complètes, le compilateur doit voir "les deux à la fois" - le code de la bibliothèque plus le modèle. valeurs de paramètre. Cela rend impossible (ou du moins difficile) de produire des unités de compilation "précompilées" pour une telle bibliothèque.
la source
Eh bien, commençons par démolir certaines de vos hypothèses:
Compiler les choses séparément signifie potentiellement ne pas avoir à tout recompiler si seulement une partie change.
Donc, un inconvénient au lieu d’un avantage.
Oui, le seul effet
inline
qui reste est l'exception à la règle une définition .Malheur à vous si ces définitions sont différentes de quelque façon que ce soit.
Donc, si une fonction est interne à une unité de compilation, marquez-la
static
. Cela rend également l’inline plus probable, car la fonction doit être disponible pour pouvoir l’intégrer.Néanmoins, jetez un coup d’œil à l’optimisation temps-lien, telle que prise en charge par au moins MSVC ++, gcc et clang.
L’un des objectifs est certainement de ne présenter que l’interface minimale, afin d’obtenir une plus grande stabilité des API et des ABI et de réduire les temps de compilation.
En particulier, les classes C ++ ne sont pas vraiment adaptées à cela, car tous les bits privés s'infiltrent dans l'en-tête, de même que les objets protégés, que vous souhaitiez en dériver ou non.
Le modèle de conception PIMPL sert à réduire ces détails.
La partie où la séparation de l'interface et de l'implémentation échoue complètement en C ++ est bien celle des modèles.
Le comité a essayé de faire quelque chose avec les modèles exportés , mais ceux-ci ont été abandonnés car trop compliqués et ne fonctionnaient pas vraiment.
Maintenant, ils travaillent sur un système de modules approprié , bien que cela avance lentement. Cela réduira considérablement les temps de compilation et devrait également augmenter la stabilité des API et des ABI en diminuant leur surface.
Les bibliothèques contenant uniquement des en-têtes peuvent être plus efficaces en termes de taille de code et de temps d'exécution, bien que cela dépende de savoir si la bibliothèque est partagée, quelle est son utilisation, de quelle manière, et si l'inlining s'avère un gain décisif dans ce cas spécifique.
Et la raison pour laquelle l'optimisation est si importante pour l'optimisation ne tient pas à son dynamisme, mais à ses possibilités de propagation constante et d'optimisation.
la source