Quels sont les avantages d'une bibliothèque d'en-tête uniquement et pourquoi l'écririez-vous de cette façon pour vous opposer à la mise en œuvre dans un fichier séparé?
Il existe des situations où une bibliothèque uniquement en-tête est la seule option, par exemple lors de l'utilisation de modèles.
Avoir une bibliothèque uniquement en-tête signifie également que vous n'avez pas à vous soucier des différentes plates-formes où la bibliothèque peut être utilisée. Lorsque vous séparez l'implémentation, vous le faites généralement pour masquer les détails de l'implémentation et distribuer la bibliothèque sous la forme d'une combinaison d'en-têtes et de bibliothèques (lib
, dll
ou .so
des dossiers). Ceux-ci doivent bien sûr être compilés pour tous les différents systèmes d'exploitation/versions que vous proposez.
Vous pouvez également distribuer les fichiers d'implémentation, mais cela signifierait une étape supplémentaire pour l'utilisateur - compiler votre bibliothèque avant de l'utiliser.
Bien sûr, cela s'applique sur une base au cas par cas. Par exemple, les bibliothèques uniquement en-tête augmentent parfois taille du code et temps de compilation.
Avantages de la bibliothèque d'en-tête uniquement:
Inconvénients d'une bibliothèque uniquement en-tête:
Fichiers d'objets plus volumineux. Chaque méthode en ligne de la bibliothèque utilisée dans un fichier source recevra également un symbole faible, une définition hors ligne dans le fichier objet compilé pour ce fichier source. Cela ralentit le compilateur et ralentit également l'éditeur de liens. Le compilateur doit générer tout ce ballonnement, puis l'éditeur de liens doit le filtrer.
Compilation plus longue. En plus du problème de ballonnement mentionné ci-dessus, la compilation prendra plus de temps car les en-têtes sont intrinsèquement plus grands avec une bibliothèque uniquement en-tête qu'une bibliothèque compilée. Ces gros en-têtes devront être analysés pour chaque fichier source qui utilise la bibliothèque. Un autre facteur est que ces fichiers d'en-tête dans une bibliothèque uniquement en-tête doivent avoir #include
En-têtes requis par les définitions en ligne ainsi que les en-têtes qui seraient nécessaires si la bibliothèque avait été construite comme une bibliothèque compilée.
Compilation plus embrouillée. Vous obtenez beaucoup plus de dépendances avec une bibliothèque uniquement en-tête à cause de ces #include
Supplémentaires nécessaires avec une bibliothèque uniquement en-tête. Modifiez l'implémentation d'une fonction clé dans la bibliothèque et vous devrez peut-être recompiler l'intégralité du projet. Apportez cette modification dans le fichier source d'une bibliothèque compilée et tout ce que vous avez à faire est de recompiler ce fichier source de bibliothèque, de mettre à jour la bibliothèque compilée avec ce nouveau fichier .o et de reconnecter l'application.
Plus difficile à lire pour l'humain. Même avec la meilleure documentation, les utilisateurs d'une bibliothèque doivent souvent recourir à la lecture des en-têtes de la bibliothèque. Les en-têtes d'une bibliothèque uniquement en-tête sont remplis de détails d'implémentation qui gênent la compréhension de l'interface. Avec une bibliothèque compilée, tout ce que vous voyez est l'interface et un bref commentaire sur ce que fait l'implémentation, et c'est généralement tout ce que vous voulez. C'est vraiment tout ce que vous voulez. Vous ne devriez pas avoir à connaître les détails de l'implémentation pour savoir comment utiliser la bibliothèque.
Je sais que c'est un vieux fil, mais personne n'a mentionné d'interfaces ABI ou de problèmes de compilation spécifiques. J'ai donc pensé que je le ferais.
Ceci est essentiellement basé sur le concept de vous, soit d'écrire une bibliothèque avec un en-tête à distribuer aux gens, soit de vous réutiliser par rapport à tout avoir dans un en-tête. Si vous songez à réutiliser un en-tête et des fichiers source et à les recompiler dans chaque projet, cela ne s'applique pas vraiment.
Fondamentalement, si vous compilez votre code C++ et créez une bibliothèque avec un compilateur, l'utilisateur essaie d'utiliser cette bibliothèque avec un compilateur différent ou une version différente du même compilateur, vous pouvez obtenir des erreurs de l'éditeur de liens ou un comportement d'exécution étrange en raison d'une incompatibilité binaire.
Par exemple, les éditeurs de compilateurs modifient souvent leur implémentation de la STL entre les versions. Si vous avez une fonction dans une bibliothèque qui accepte un vecteur std :: alors elle s'attend à ce que les octets de cette classe soient organisés de la même manière qu'ils ont été arrangés lors de la compilation de la bibliothèque. Si, dans une nouvelle version du compilateur, le fournisseur a amélioré l'efficacité de std :: vector, le code de l'utilisateur voit la nouvelle classe qui peut avoir une structure différente et transmet cette nouvelle structure à votre bibliothèque. Tout se déroule à partir de là ... C'est pourquoi il est recommandé de ne pas faire passer les objets STL au-delà des limites de la bibliothèque. Il en va de même pour les types C Run-Time (CRT).
Lorsque vous parlez du CRT, votre bibliothèque et le code source de l'utilisateur doivent généralement être liés au même CRT. Avec Visual Studio, si vous créez votre bibliothèque à l'aide du CRT multithread, mais que l'utilisateur se connecte au CRT de débogage multithread, vous aurez des problèmes de lien car votre bibliothèque peut ne pas trouver les symboles dont elle a besoin. Je ne me souviens pas de quelle fonction il s'agissait, mais pour Visual Studio 2015, Microsoft a créé une fonction CRT en ligne. Du coup, ce n'était pas dans l'en-tête de la bibliothèque CRT, donc les bibliothèques qui s'attendaient à le trouver au moment du lien ne pouvaient plus le faire et cela générait des erreurs de lien. Le résultat était que ces bibliothèques devaient être recompilées avec Visual Studio 2015.
Vous pouvez également obtenir des erreurs de lien ou un comportement étrange si vous utilisez l'API Windows mais que vous créez avec différents paramètres Unicode pour l'utilisateur de la bibliothèque. Cela est dû au fait que l'API Windows possède des fonctions qui utilisent soit Unicode ou ASCII chaînes et macros/définit qui utilisent automatiquement les types corrects en fonction des paramètres Unicode du projet. Si vous passez une chaîne à travers la limite de la bibliothèque ce n'est pas le bon type, puis les choses se brisent lors de l'exécution. Ou vous pouvez constater que le programme ne se lie pas en premier lieu.
Ces choses sont également vraies pour le passage d'objets/types au-delà des limites de bibliothèque à partir d'autres bibliothèques tierces (par exemple, un vecteur propre ou une matrice GSL). Si la bibliothèque tierce change son en-tête entre vous en train de compiler votre bibliothèque et votre utilisateur en train de compiler leur code, alors les choses vont se casser.
Fondamentalement, pour être en sécurité, les seules choses que vous pouvez passer au-delà des limites de la bibliothèque sont des types intégrés et des Plain Old Data (POD). Idéalement, tout POD doit se trouver dans des structures définies dans vos propres en-têtes et ne pas s'appuyer sur des en-têtes tiers.
Si vous fournissez une bibliothèque uniquement d'en-tête, alors tout le code est compilé avec les mêmes paramètres de compilateur et contre les mêmes en-têtes, de sorte que beaucoup de ces problèmes disparaissent (la version des bibliothèques partiellement tierces que vous et vos utilisateurs utilisez sont compatibles avec l'API).
Cependant, il y a des points négatifs qui ont été mentionnés ci-dessus, comme l'augmentation du temps de compilation. De plus, vous dirigez peut-être une entreprise et vous ne voudrez peut-être pas remettre tous les détails de l'implémentation de votre code source à tous vos utilisateurs au cas où l'un d'eux le vole.
Le principal "avantage" est qu'il vous oblige à fournir du code source, vous vous retrouverez donc avec des rapports d'erreurs sur des machines et des compilateurs dont vous n'avez jamais entendu parler. Lorsque la bibliothèque est entièrement constituée de modèles, vous n'avez pas beaucoup de choix, mais lorsque vous avez le choix, l'en-tête uniquement est généralement un mauvais choix d'ingénierie. (D'un autre côté, bien sûr, l'en-tête signifie uniquement que vous n'avez à documenter aucune procédure d'intégration.)