OVH Cloud OVH Cloud

Exporter des symboles pour les nuls ( moi en fait ! )

26 réponses
Avatar
gbaudin
Bonjour,

si je crée une simple dll dans laquelle j'exporte des objets

exemple :

#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif

typedef std::map<std::string, std::string> MyMap;
class TESTDLL_API CTestDll
{
protected:
MyMap mMap;

public:
CTestDll(void);
void put( const MyMap& _map )
{
mMap.clear();

const long nbrElem = _map->size();
for ( MyMap::const_iterator it = _map->begin(); it != _map->end();
it++ )
{
std::string key = it->first;
std::string value = it->second;
mMap[key] = value;
}
}
};

//////////////////////////////////////////////////////////////

si je fais un exe qui exploite cette dll


#include "stdafx.h"
#include "testDll.h"

int main(int argc, char* argv[])
{
CTestDll dll;
MyMap map;
map["key"] = "value";
dll.put( map );
return 0;
}


Ce petit test crash dans la methode "put", mais je ne suis pas sur d'en
comprendre les raisons.
Est ce que quelqu'un peut m'eclairer ?

Du coup comment modifier mon exemple pour qu'il fonctionne ?

merci.

10 réponses

1 2 3
Avatar
Manuel Zaccaria
kanze a écrit:

Je vois déjà un problème ici. Ce typedef, en réalité,
peut représenter PLUSIEURS types.


Oui et non. En tant que type, c'est bien un seul type. En
revanche, il est clair qu'il faut que tous les objets linkés
dans le programme (qu'ils soient linké dynamiquement ou
statiquement) soit compilés avec le même compilateur et les
mêmes options. Qu'on ait une version débug dans un des fichiers
objets et une version optimisée dans un autre, et il y a des
chances que ça ne marche pas.


J'en suis conscient, je me suis assez cassé les dents dessus.

Aussi, il faut faire gaffe en ce qui concerne les parties qui
dépendent des objets statiques -- dans le cas d'un map, par
exemple, l'allocateur (qui utilise une structure statique pour
gérer la memoire). Il ne faut pas qu'ils utilisent une instance
une fois, et une autre instance une autre fois. Ce qui
correspond à des options par défaut sous Unix, mais qui, d'après
ce que j'ai entendu dire, n'est pas le défaut sous Unix.


J'essaie de ne pas avoir d'objets statiques dans mes modules.
Pour l'instant j'en ai jamais eu besoin. J'allume un cierge.

[...]

Un MyMap pour chaque dll (debug/release) plus un MyMap pour
chaque exe (debug/release) et que sais-je encore. Les options
de compilations, etc, etc. Il y a de fortes chances qu'ils
soient très différents.


A priori, dans un cas comme le sien, je dirais non. C'est un


A priori.

petit exemple ; logiquement, il aurait tout compilé avec les
mêmes options. (Note bien aussi que le problème des options
n'est pas propre au chargement dynamique. J'ai déjà eu des
problèmes parce que certains objets avaient été compilé avec
debug, d'autres non, avec g++ et linké statiquement.)


Et dans six mois ? Il faut recompiler les 50 modules car on a
une nouvelle version du compilateur ?

Pas simplement en tous cas.. là, je dois partir maintenant.
Mais juste un conseil: utiliser des POD, pas des classes. (et
surtout qu'en plus ce sont des templates ce qui n'aide pas)


Je ne sais pas. Je me sers regulièrement des classes assez
complexes dans les objets dynamiques. Typiquement, d'ailleurs,
ce que j'exporte est une classe d'interface : que des fonctions
virtuelles pûres. L'objet dynamique contient une fonction usine
pour les créer, et le code utilisateur ne voit jamais de membres
donnés ni de fonction directement. Dans la pratique, ça permet
de compiler avec des options différentes aussi. (Note qu'avec
cette solution, dans son cas, le map n'apparaîtra que dans la
DLL.)


Je suis absolument d'accord et je le fais souvent car une classe
d'interface n'exprime qu'un contrat et ne pollue pas le client.
Les usines sont aussi un composant essentiel; les objets que
je crée avec sont détruits à coup de 'delete this' et ils ont
tous un destructeur inaccessible au code client (y compris les
interfaces, il n'y a pas de destructeur virtuel dans ce cas).


Manuel


Avatar
Arnaud Debaene
"Manuel Zaccaria" a écrit dans le message de
news: c2411$44beb405$544a9ed1$
kanze a écrit:


Et dans six mois ? Il faut recompiler les 50 modules car on a
une nouvelle version du compilateur ?


J'ai du mal a saisir le raisonnement : En quoi recompiler les 600000 lignes
de code source répartis en 50 modules est-il fondamentalement plus difficile
que de recompiler les même 60000 lignes de code source compilés en un seul
exe?
Si on veut passer a une nouvelle version du compilateu, on le fait
entièrement, point barre...

La vraie difficulté surgit quand la DLL est utilisée par différents clients,
utilisant différents outils de développement...

Arnaud

Avatar
Sylvain
Manuel Zaccaria wrote on 20/07/2006 00:36:
[...]
Je suis absolument d'accord et je le fais souvent car une classe
d'interface n'exprime qu'un contrat et ne pollue pas le client.
Les usines sont aussi un composant essentiel; les objets que
je crée avec sont détruits à coup de 'delete this' et ils ont
tous un destructeur inaccessible au code client (y compris les
interfaces, il n'y a pas de destructeur virtuel dans ce cas).


des dll basées sur une interface publique, une gestion mémoire confinée
à la librairie (notamment un public dispose(){delete this;}) et des
factory statiques permettent d'obtenir du code prédictif et stable
(nombre d'architecture marshalées fonctionnent comme cela).

les simples changements de compilo ne condamment pas à la recompil
globale (seuls des basiques comme la convention d'appel (M$ spécifique?)
ou la taille d'un int (32 ou 64) devront évidemment être constants).

Sylvain.

Avatar
kanze
Loïc Joly wrote:

En général, le chargement dynamique est une source de problèmes
et d'instabilités. On l'évite quand on n'en as pas explicitement
besoin -- dans un programme applicatif qui ne supporte pas de
plugins, il n'y a que des bibliothèques du système et des
produits tièrce (base de données, etc.) qui doivent être chargé
dynamique. Mettre diverses parties de l'application dans de
différentes DLL's n'a que de désavantages.


Le problème viens dès que l'on a des plug-ins.


Non seulement. Il y a des problèmes liés aux plug-ins, mais il y
a un problème général lié au chargement dynamique : c'est qu'il
est dynamique. C-à-d qu'il a lieu à un moment et dans un
environement que toi, le développeur, ne contrôle pas. Quand tu
fais un link statique, par exemple, c'est à toi de s'assurer que
toutes les versions se concordent, et une fois que c'est linké,
tu es garantie des versions qu'utilise le programme à jamais.
Avec une édition de liens dynamiques, en revanche, tu es à la
merci de l'environement utilisateur, et le fait que tu as linké
les bonnes versions chex toi n'est pas réelement une garantie.

Je me retrouve très souvent dans le cas où j'ai des plug-ins
qui utilisent une infrastructure commune. Et bien, je me
retrouve souvent obligé de mettre cette architecture dans une
DLL aussi, car sinon, la mémoire globale (et donc les
singletons) gérée pas cette bibliothèque se trouve dupliquée
par DLL de plug-in, ce qui n'est pas sans poser de problèmes.


Je ne connais pas Windows, mais est-ce qu'il ne serait pas
possible de forcer sa présence dans la racine, et que tous les
plug-ins s'en servent de l'instance là ? (C'est rélativement
simple sous Unix.)

Note aussi qu'il y a une grande différence entre Unix et Windows
sur un point assez critique ici. Sous Unix, la bibliothèque
standard de C, ainsi que l'interface Posix, et prèsque linké
dynamiquement, ET bundlé avec le système. Du coup, tu es garanti
n'avoir qu'une instance des fonctions comme malloc et free. Si
j'ai bien compris, sous Windows, par défaut, l'API système et la
bibliothèque C sont linkée statiquement, et surtout, la DLL qui
en correspond est livrée avec le compilateur, et n'est pas
présente par défaut sur les systèmes où il n'y a pas de
compilateur. Ce qui ajoute un peu à la complexité de la
diffusion (une DLL de plus dans le package), et explique le
défaut de les linker statiquement.

Autre cas d'utilisation de DLL : .NET... Il n'y a pas de
linker avec ce framework, et tout passe donc par des
bibliothèques dynamiques :(


Je ne suis pas sûr de comprendre. Sous Unix, et sous les Windows
classiques pré-.NET, il n'y a pas de bibliothèques dynamiques ;
malgré leur nom, une DLL se comporte comme un fichier objet en
partie pré-linké. Et il faut bien quelque chose du genre d'un
éditeur de liens pour les construire. (Sous Unix, c'est bien
l'éditeur de liens classique, ld, qui le fait. J'ai l'impression
que c'est aussi ce qui se passe quand je donne l'option /LD à
cl : il invoque link avec l'option /DLL.)

Ou est-ce que .NET fonctionne un peu comme Java, où les fichiers
.jar sont réelement des bibliothèques, et que les composants en
sont réelement extraits et linkés lors de l'exécution, sans
jamais avoir été linkés entre eux avant ? (C'est un des grands
défauts de Java, qui fait qu'on ne peut pas s'en servir dans
certaines applications, où la sécurité ou la fiabilité sont
des critères importants.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
kanze
Manuel Zaccaria wrote:
gbaudin a écrit:

Je n'aurais pas penser que le type template pouvait
provoquer cette erreur


Ce n'est pas ce que j'ai dit. Avec les templates, le code
client a une dépendance facheuse avec l'implémentation,
private ou pas. Ca aide ça ?

J'ai quand même du mal a comprendre pourquoi
map<string,string> n'est pas considéré de même type dans
l'exe et dans la dll ...


Oh mais pour le compilateur il s'agît du même type (comme
James Kanze l'a justement souligné) mais quand on ment au
compilateur... il se venge.


Tout à fait.

Un peu d'histoire ici est intéressante. Le C++ a toujours été
assez sensibles sur l'organisation des classes (et les chose qui
en dépendent, comme les vtables). Organisation qui souvent n'est
pas normalisée par la plateforme, et qui varie en fait d'un
compilateur à l'autre, et même entre différentes versions du
même compilateur. Alors, chaque compilateur décore ses noms
différemment, et du coup, si tu essaies de linker des fichiers
objets des compilateurs différents, tu as une erreur, parce que
les noms décorés dans un fichier objet ne correspondent pas à
ceux dans l'autre fichier objet. Aussi, quand l'évolution du
compilateur fait que l'organisation des classes a changée, le
compilateur change la décoration des noms, de façon à ce que les
versions incompatibles ne passent pas l'éditeur de liens.
(Dynamique ou statique, ça fait rien.)

Actuellement, ce qu'on constate (au moins avec g++ et VC++),
c'est qu'il y a maintenant des variants dans la bibliothèque,
qui dépend des options de compilation. Donc, si je compile avec
g++ (4.1.0) sans options particulières, sizeof(vector<int>) est
12 ; si je compile avec l'option -D_GLIBCXX_DEBUG, c'est 28. Et
c'est clair que si je melange les deux dans un seul programme,
ça ne va pas marcher. Du point de vue de l'utilisateur (qui
considère std::vector comme faisant partie du langage), c'est
comme ci j'ai changé le compilateur avec une option. Sauf que
techniquement, ce qui est réelement le compilateur ne le sait
pas, et donc évidemment ne peut pas changer la décoration. Et
donc, ton programme linke bien (statiquement ou
dynamiquement -- une fois de plus, ça ne change rien).

Ce qui est dommage, parce qu'il existe une solution assez
simple : dans la décoration du nom d'une classe, on ajoute un
hachage des tokens dans la définition de la classe. Du coup,
quand les définitions des classes diffèrent suite à une option
de compilation, comme ici, le nom décoré sera différent, et on
aurait une erreur à l'édition de liens.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
kanze
Manuel Zaccaria wrote:
kanze a écrit:

Je vois déjà un problème ici. Ce typedef, en réalité,
peut représenter PLUSIEURS types.


Oui et non. En tant que type, c'est bien un seul type. En
revanche, il est clair qu'il faut que tous les objets linkés
dans le programme (qu'ils soient linké dynamiquement ou
statiquement) soit compilés avec le même compilateur et les
mêmes options. Qu'on ait une version débug dans un des
fichiers objets et une version optimisée dans un autre, et
il y a des chances que ça ne marche pas.


J'en suis conscient, je me suis assez cassé les dents dessus.


C'est néaumoins une nouveauté, due à l'introduction des versions
de déboggage de la bibliothèque standard.

Aussi, il faut faire gaffe en ce qui concerne les parties
qui dépendent des objets statiques -- dans le cas d'un map,
par exemple, l'allocateur (qui utilise une structure
statique pour gérer la memoire). Il ne faut pas qu'ils
utilisent une instance une fois, et une autre instance une
autre fois. Ce qui correspond à des options par défaut sous
Unix, mais qui, d'après ce que j'ai entendu dire, n'est pas
le défaut sous Unix.


J'essaie de ne pas avoir d'objets statiques dans mes modules.
Pour l'instant j'en ai jamais eu besoin. J'allume un cierge.


Tu n'utilises jamais new et delete, ni des objets qui les
utilisent ? Parce que la gestion de la mémoire dynamique se
répose sur des objets statiques.

[...]

Et dans six mois ? Il faut recompiler les 50 modules car on a
une nouvelle version du compilateur ?


De toute façon. Depuis toujours. Ça a toujours été le cas :
l'installation d'une nouvelle version du compilateur (voire même
des patchs) exige un nouveau build complet. Même dans le cas où
c'est réputé « objet compatible ». (L'objet compatible sert
surtout dans le cas des bibliothèques tièrces, où on n'a pas les
sources, et où il faut payer pour une nouvelle versions.)

Dans la plupart des boîtes où j'ai travaillé, la politique était
de périodiquement faire un rebuild complète de toute façon,
histoire de ne pas prendre des risques. Un petit cron job qui
tournait tous les week-end, par exemple.

Pas simplement en tous cas.. là, je dois partir maintenant.
Mais juste un conseil: utiliser des POD, pas des classes.
(et surtout qu'en plus ce sont des templates ce qui n'aide
pas)


Je ne sais pas. Je me sers regulièrement des classes assez
complexes dans les objets dynamiques. Typiquement,
d'ailleurs, ce que j'exporte est une classe d'interface :
que des fonctions virtuelles pûres. L'objet dynamique
contient une fonction usine pour les créer, et le code
utilisateur ne voit jamais de membres donnés ni de fonction
directement. Dans la pratique, ça permet de compiler avec
des options différentes aussi. (Note qu'avec cette solution,
dans son cas, le map n'apparaîtra que dans la DLL.)


Je suis absolument d'accord et je le fais souvent car une
classe d'interface n'exprime qu'un contrat et ne pollue pas le
client. Les usines sont aussi un composant essentiel; les
objets que je crée avec sont détruits à coup de 'delete this'
et ils ont tous un destructeur inaccessible au code client (y
compris les interfaces, il n'y a pas de destructeur virtuel
dans ce cas).


Ce qui n'est pas une mauvaise précaution, même si ce n'est pas
toujours nécessaire.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
kanze
Sylvain wrote:
Manuel Zaccaria wrote on 20/07/2006 00:36:
[...]
Je suis absolument d'accord et je le fais souvent car une classe
d'interface n'exprime qu'un contrat et ne pollue pas le client.
Les usines sont aussi un composant essentiel; les objets que
je crée avec sont détruits à coup de 'delete this' et ils ont
tous un destructeur inaccessible au code client (y compris les
interfaces, il n'y a pas de destructeur virtuel dans ce cas).


des dll basées sur une interface publique, une gestion mémoire
confinée à la librairie (notamment un public dispose(){delete
this;}) et des factory statiques permettent d'obtenir du code
prédictif et stable (nombre d'architecture marshalées
fonctionnent comme cela).

les simples changements de compilo ne condamment pas à la
recompil globale (seuls des basiques comme la convention
d'appel (M$ spécifique?) ou la taille d'un int (32 ou 64)
devront évidemment être constants).


Il vaut mieux que l'organisation de la vtable ne change pas non
plus, si tu te sers d'une interface. Ni la structure des données
passées en paramètre (par valeur ou par référence) : n'essaie
pas de passer un std::string d'une module compilée avec VC++ 6 à
une module compilée avec VC++ 2005. (D'après mes souvenirs,
sizeof( std::string ) était 4 dans VC++ 6 ; c'est 28 avec VC++
2005.)

N'essaie pas, d'ailleurs, de passer un std::vector<int> d'une
module compilée avec VC++ 2005 avec les options /MTd et une
autre compilée sans cette option. (Ce qui nous ramène à la
question du départ.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Loïc Joly
Je me retrouve très souvent dans le cas où j'ai des plug-ins
qui utilisent une infrastructure commune. Et bien, je me
retrouve souvent obligé de mettre cette architecture dans une
DLL aussi, car sinon, la mémoire globale (et donc les
singletons) gérée pas cette bibliothèque se trouve dupliquée
par DLL de plug-in, ce qui n'est pas sans poser de problèmes.



Oui. Le problème est que j'aurais amé linker statiquement ce composant
dans le module, et que je suis obligé de le lier dynamiquement.

Autre cas d'utilisation de DLL : .NET... Il n'y a pas de
linker avec ce framework, et tout passe donc par des
bibliothèques dynamiques :(



Je ne suis pas sûr de comprendre. Sous Unix, et sous les Windows
classiques pré-.NET, il n'y a pas de bibliothèques dynamiques ;
malgré leur nom, une DLL se comporte comme un fichier objet en
partie pré-linké.


Par focément. On peut se lier statiquement avec une DLL, par
l'intermédiaire par exemple d'un .lib d'import, mais on peut aussi s'y
lier dynamiquement (avec des fonction LoadLibrary, GetProcAdress...).

Et il faut bien quelque chose du genre d'un
éditeur de liens pour les construire. (Sous Unix, c'est bien
l'éditeur de liens classique, ld, qui le fait. J'ai l'impression
que c'est aussi ce qui se passe quand je donne l'option /LD à
cl : il invoque link avec l'option /DLL.)

Ou est-ce que .NET fonctionne un peu comme Java, où les fichiers
.jar sont réelement des bibliothèques, et que les composants en
sont réelement extraits et linkés lors de l'exécution, sans
jamais avoir été linkés entre eux avant ? (C'est un des grands
défauts de Java, qui fait qu'on ne peut pas s'en servir dans
certaines applications, où la sécurité ou la fiabilité sont
des critères importants.)


Je ne connais pas vraiment Java, aussi il y a des chances que je réponde
à côté.

Les DLL externes sont utilisée à l'exécution, bien évidemment, mais
aussi à la compilation, où elles ont pour seul(*) but de permettre par
de l'introspection de publier leur contenu, remplaçant ainsi les .h.

Et il est aussi possible de se lier avec des DLL.NET dont on ne connait
rien a priori, puisqu'on peut en obtenir tout un tas d'information au
run-time (genre : Bon, donne moi toutes les classes qui
implémententtelle interface et on un constructeur sans paramètre, puis
contruit moi une instance de celles-ci).

Le problème est que les modules (les DLL) définissent la granularité de
base des certains points du framework, comme le partage de code, un
certain aspect de visibilité,... Ce qui incite presque dans certains cas
à avoir un module par classe. Et là, ça fait beaucoup de DLL...

Donc, il n'y a pas un module par fichier ou par classe obligatoirement,
mais les modules on tendance à être assez petits si on veut faire du
code réutilisable, et il manque un outil permettant de packager
plusieurs modules en un seul, afin d'éviter les problèmes d'installation.


--
Loïc



(*) Pour les DLL.NET classiques, les DLL de contrôles, par exemple,
exécutent le contrôle dans l'outil de design de formulaire pendant qu'on
code.


Avatar
Sylvain
Loïc Joly wrote on 20/07/2006 21:38:

Je ne suis pas sûr de comprendre. Sous Unix, et sous les Windows
classiques pré-.NET, il n'y a pas de bibliothèques dynamiques ;
malgré leur nom, une DLL se comporte comme un fichier objet en
partie pré-linké.


Par focément. On peut se lier statiquement avec une DLL, par
l'intermédiaire par exemple d'un .lib d'import, mais on peut aussi s'y
lier dynamiquement (avec des fonction LoadLibrary, GetProcAdress...).


statique ou dynamique peut être trompeur; comme vous en parlez, il
s'agit dans les 2 cas d'un même fichier (.dll), distinct de l'appli et
construit d'une seule façon. il peut être "dynamiquement" remplacé (s'il
est buggé ou incomplet) du moment qu'il respecte la même table d'export.

une "librairie statique" au sens M$ (un fichier ".lib d'implémentation")
est un simple pool de .obj pré-linkés.

la différence est simplement qu'une DLL liée statiquement (par import de
son ".lib d'export") est montée d'autorité par le code de démarrage de
l'appli - qui plante donc avec une alerte système si la DLL est absente
ou invalide - alors que monter dynamiquement une DLL permet de le faire
à la demande et avec une gestion plus souple des cas d'erreurs (absente,
trop vieille, etc).

Et il faut bien quelque chose du genre d'un
éditeur de liens pour les construire. (Sous Unix, c'est bien
l'éditeur de liens classique, ld, qui le fait. J'ai l'impression
que c'est aussi ce qui se passe quand je donne l'option /LD à
cl : il invoque link avec l'option /DLL.)



dans le cas d'un DLL statique, un .lib (table d'export) est contruit
avec la librairie et pris en entrée du linker de l'appli; on peut alors
avoir accès à des classes ou des méthodes "C statiques" exportées.

pour une DLL dynamique, on se paluche le travail à la main pour
récupérer des pointeurs de fonctions - sauf erreur, on ne peut importer
de la lib la définition d'une classe; on peut par contre mettre le code
de la classe de base dans l'appli (le dupliquer!) et utiliser une
factory statique pour obtenir de la lib. une instance concrête de type
inconnu (connu de la lib seule).

Ou est-ce que .NET fonctionne un peu comme Java, où les fichiers
.jar sont réelement des bibliothèques, et que les composants en
sont réelement extraits et linkés lors de l'exécution, sans
jamais avoir été linkés entre eux avant ? (C'est un des grands
défauts de Java, qui fait qu'on ne peut pas s'en servir dans
certaines applications, où la sécurité ou la fiabilité sont
des critères importants.)



non Java repose sur un class loader pour charger depuis un .class ou un
.jar le code d'une classe connue au moment où le client a été compilé.
java-beans a ajouté la réflectivité pour permettre de charger des choses
inconnues et les utiliser ensuite (de manière tordue et dispendieuse).

le class loader peut être supplanté si des besoins sécuritaires impose
le chargement des classes depuis une source sure; le chargement à
l'aveugle du premier fichier ayant le bon nom existe pareillement en C++
(sous linux comme Wintel).

Les DLL externes sont utilisée à l'exécution, bien évidemment, mais
aussi à la compilation, où elles ont pour seul(*) but de permettre par
de l'introspection de publier leur contenu, remplaçant ainsi les .h.


dans le cas de .NET

Donc, il n'y a pas un module par fichier ou par classe obligatoirement,
mais les modules on tendance à être assez petits si on veut faire du
code réutilisable, et il manque un outil permettant de packager
plusieurs modules en un seul, afin d'éviter les problèmes d'installation.


je dirais les problèmes de pollution (création d'une plétore de fichiers
sur la machine de l'utilisateur final) plus que d'installation stricte
(si on peut installer 1 DLL, on peut en installer N); le découpage
permet également de patcher à moindre frais de transfert (une petite DLL
de qlq centaines de Ko plutôt qu'une assemblie de plusieurs mégas).

Sylvain.


Avatar
Sylvain
kanze wrote on 20/07/2006 11:55:

Il vaut mieux que l'organisation de la vtable ne change pas non
plus, si tu te sers d'une interface. Ni la structure des données


M$ a des directives à lui comme __declspec(novtable) qui permettent de
ne pas avoir de vtable sur la "classe d'interface" (la classe aux
méthodes abstraites pures); dans les cas les plus exigeants ça permet de
minimiser les dépendances (au prix d'un marshaling).

passées en paramètre (par valeur ou par référence) : n'essaie
pas de passer un std::string d'une module compilée avec VC++ 6 à
une module compilée avec VC++ 2005.


je n'essaierais jamais de passer le moindre template entre 2 codes
distincts, c'est perdre son temps et finalement inefficace (par
comparaison à 2 méthodes foo(char*) et foo(wchar_t*) plus pereines par
exemple).

N'essaie pas, d'ailleurs, de passer un std::vector<int> d'une
module compilée avec VC++ 2005 avec les options /MTd et une
autre compilée sans cette option. (Ce qui nous ramène à la
question du départ.)


non plus (j'utilise d'ailleurs jamais vector ayant un template à moi),
les exemples ne manquent pas pour dire que si on doit transmettre une
instance compilo dépendante, on ne le fera que de la source de cette
instance vers elle-même (ie se limiter à transmettre un pointeur) et on
s'interdira de l'utiliser ailleurs ... ce qui rends la manip. totalement
inutile.

Sylvain.

1 2 3