Les bibliothèques d'en-tête seulement sont-elles plus efficaces?

49

Hypothèses

  1. 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.

  2. En C et C ++ inlinen'a de sens que si la fonction est définie dans un fichier d'en-tête *.

  3. 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

Vorac
la source
2
Vous seriez surpris de la capacité d'un grand nombre de lieurs C ++ modernes (GCC, MSVC, ICC, etc.) à intégrer du code dans des unités de traduction distinctes. Je dirais «généralement non» du point de vue de l'efficacité, compte tenu du nombre de fois que l'optimisation des linkers a défié mes attentes et a réussi à se mettre en ligne de toute façon (cela exclut les contextes dylib où insérer une en-tête ou fournir l'implémentation dans une bibliothèque séparée liée statiquement peut aider). . Pourtant, les bibliothèques contenant uniquement des en-têtes peuvent être très sexy, à condition qu’elles soient stables à la fois en interface et en implémentation, en raison de la facilité avec laquelle elles peuvent être déployées dans de nouveaux projets.
1
Je ne sais pas si cela mérite une réponse complète, mais l'un des grands avantages des bibliothèques d'en-tête est la facilité d'installation et d'utilisation: Téléchargez, #include "lib.h (pp)", c'est fait.
WeRelic

Réponses:

45

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.

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.

En C et C ++, Inline n’a de sens que si la fonction est définie dans un fichier d’en-tête *

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.

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.

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.

Doc Brown
la source
6
En bref, les bibliothèques contenant uniquement des en-têtes sont plus pratiques que plus efficaces ; et comme C ++ n’a pas de gestionnaire de paquets standard, cela favorise l’adoption.
Matthieu M.
6
@MatthieuM: non, le code compilé peut en effet parfois être plus efficace, et pour les bibliothèques de modèles, la conception en-tête uniquement n'est généralement pas une question de commodité. Et l'augmentation des temps compilés n'est certainement pas plus pratique.
Doc Brown
Avoir le code à chaud dans les en-têtes pourrait en effet conduire à un code compilé plus efficace, mais cela n'exige pas d'avoir tout le code dans les en-têtes et est donc indépendant, à mon humble avis, à partir de bibliothèques en-tête uniquement.
Matthieu M.
1
@MatthieuM .: c'est sûrement correct, néanmoins je pense que le terme "plus pratique" ne décrit pas bien le cas.
Doc Brown
3
J'ai travaillé sur un grand projet intégré sur un système d'exploitation réduit et ancien pour mon précédent employeur, et dans ces cas, je peux témoigner de la douleur liée aux longs temps de compilation. Quiconque pris trop dans les fichiers d'en-tête serait traité impitoyablement.
Fred Thomsen
15

Eh bien, commençons par démolir certaines de vos hypothèses:

  1. 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.

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.

  1. En C et C ++, Inline n’a de sens que si la fonction est définie dans un fichier d’en-tête *.

Oui, le seul effet inlinequi 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.

  1. 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.

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 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?

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.

Déduplicateur
la source