Comment utiliser les classes Standard Library (STL) dans mon interface dll ou ABI?

Il y a eu quelques questions sur l’exportation d’une classe contenant des classes stl par rapport à l’avertissement visuel en studio C4251: par exemple, cette question ou cette question. J’ai déjà lu l’excellente explication sur UnknownRoad.

Désactiver aveuglément l’avertissement semble un peu dangereux, même si cela peut être une option. Envelopper toutes ces classes standard et les exporter n’est pas vraiment une option. Il s’agit après tout de la bibliothèque de modèles standard , c’est-à-dire que l’on veut fournir une interface avec ces classes standard.

Comment utiliser les classes stl dans mon interface dll? Quelles sont les pratiques courantes?

Gardez à l’esprit une chose avant de lire plus loin: Ma réponse provient du sharepoint vue de l’écriture de code portable pouvant être utilisé dans des applications composées de modules compilés sous différents compilateurs. Cela peut inclure différentes versions ou même différents niveaux de patch du même compilateur.

Comment utiliser les classes stl dans mon interface dll?

Réponse: Vous ne pouvez souvent pas 1 .

Raison: La STL est une bibliothèque de code, pas une bibliothèque binary comme une DLL. Il ne dispose pas d’une seule interface ABI garantie identique partout où vous pouvez l’utiliser. En effet, STL est synonyme de « Standard Template Library», mais un mot clé ici, outre Standard est Template .

La norme définit les méthodes et les données que chaque classe STL doit fournir, et définit ce que ces méthodes doivent faire. mais pas plus. En particulier, la norme ne spécifie pas comment les créateurs de compilateurs doivent implémenter la fonctionnalité définie par la norme. Les créateurs de compilateurs sont libres de fournir une implémentation d’une classe STL qui ajoute des fonctions membres et des variables membres non répertoriées dans la norme, à condition que les membres définis dans la norme soient toujours là et répondent aux spécifications du standard.

Peut-être qu’un exemple est en ordre. La classe basic_ssortingng est définie dans le standard comme ayant certaines fonctions et variables membres. La définition actuelle est presque 4 pages dans la norme, mais voici un extrait:

 namespace std { template, class Allocator = allocator > class basic_ssortingng { [snip] public: // 21.3.3 capacity: size_type size() const; size_type length() const; size_type max_size() const; void resize(size_type n, charT c); void resize(size_type n); size_type capacity() const; void reserve(size_type res_arg = 0); void clear(); bool empty() const; [snip] }; 

Considérez les fonctions membres size() et length() . Il n’y a rien dans la norme qui spécifie les variables membres pour contenir ces informations. En effet, il n’y a aucune variable membre définie, même pas pour contenir la chaîne elle-même. Alors, comment cela est-il mis en œuvre?

La réponse est, de nombreuses manières différentes. Certains compilateurs peuvent utiliser une variable membre size_t pour contenir la taille et un caractère char* pour contenir la chaîne. Un autre pourrait utiliser un pointeur vers un autre magasin de données contenant ces données (cela pourrait être le cas dans une implémentation avec référence). En fait, différentes versions ou même des niveaux de patch du même compilateur peuvent modifier ces détails d’implémentation. Vous ne pouvez pas compter sur eux. Ainsi, l’implémentation de MSVC 10 pourrait ressembler à ceci:

 namespace std { template, class Allocator = allocator > class basic_ssortingng { [snip] char* m_pTheSsortingng; }; size_t basic_ssortingng::size() const { return strlen(m_pTheSsortingng;) } 

… alors que MSVC 10 avec SP1 pourrait ressembler à ceci:

 namespace std { template, class Allocator = allocator > class basic_ssortingng { [snip] vector m_TheSsortingng; }; size_t basic_ssortingng::size() const { return m_TheSsortingng.size(); } 

Je ne dis pas qu’ils ressemblent à ceci, je dis qu’ils pourraient. Le point ici est que l’implémentation réelle dépend de la plate-forme, et vous n’avez vraiment aucun moyen de savoir ce que ce sera ailleurs.

Maintenant, dites que vous utilisez MSVC10 pour écrire une DLL qui exporte cette classe:

 class MyGizmo { public: std::ssortingng name_; }; 

Quelle est la sizeof(MyGizmo) ?

En supposant mes implémentations proposées ci-dessus, sous MSVC10, il s’agira de sizeof(char*) , mais sous SP1, il s’agira de sizeof(vector) . Si vous écrivez une application dans VC10 SP1 qui utilise la DLL, la taille de l’object sera différente de la réalité. L’interface binary est modifiée.


Pour un autre traitement, consultez le numéro 63 de C ++ Coding Standards ( lien Amazon).


1 : ” Vous ne pouvez pas souvent ” Vous pouvez en fait exporter des composants de la bibliothèque standard ou tout autre composant de la bibliothèque de code (tel que Boost) avec une certaine fiabilité lorsque vous contrôlez entièrement les chaînes d’outils et les bibliothèques.

Le problème fondamental est que, avec les bibliothèques de code source, les tailles et les définitions des choses peuvent être différentes entre différents compilateurs et différentes versions de la bibliothèque. Si vous travaillez dans un environnement où vous contrôlez ces deux éléments partout où votre code est utilisé, vous n’aurez probablement pas de problème. Par exemple, dans une entreprise commerciale où tous les systèmes sont écrits en interne et utilisés en interne, il peut être possible de le faire.