2009-07-06 12 views
2

J'ai écrit une application qui permet aux gens de contribuer des plugins pour étendre la fonctionnalité. Ces plugins sont déployés en tant que fichiers DLL, que le framework récupère lors de l'exécution. Chaque plugin dispose d'une fonction usine appelée plusieurs fois pendant la durée de vie de l'application pour créer des objets. Jusqu'à présent, afin de gérer le problème de propriété avec ces objets, j'ai utilisé un simple pointeur de comptage partagé sur les objets retournés afin qu'ils soient détruits chaque fois que la dernière référence est supprimée. Cependant, ceci a tendance à déclencher des plantages sur Windows car il n'est pas improbable que l'objet soit nouveau dans la DLL du plugin mais plus tard (en raison d'un appel deref() sur le pointeur partagé) supprimé dans l'application principale - et AFAIK ce mixage malloc/libre est un non-non sur Windows.DLL mélange manager de gestion

Ma solution actuelle est de laisser deref() ne pas appeler 'supprimer ceci'; directement mais plutôt une 'release();' fonction qui doit être implémentée par les plugins et les appels 'delete this'. Cependant, il est assez ennuyeux que chaque plugin doit implémenter cette fonction triviale - j'ai travaillé autour de cela jusqu'à présent en fournissant une macro de commodité que les auteurs doivent utiliser. Est-ce que quelqu'un a des idées alternatives peut-être? Jusqu'ici, mon approche est que tous les objets contribués par les plugins sont alloués dans les plugins et aussi libérés là - bien sûr, une alternative pourrait être de laisser toute la mémoire être allouée dans l'application principale (en fournissant un pointeur vers un fonction malloc-like aux plugins qu'ils peuvent ensuite appeler au besoin) et libérés là aussi. Le problème avec ceci est que ce n'est pas aussi pratique pour les auteurs de plugins, je pense.

Je serais intéressé par d'autres perspectives sur ce sujet.

MISE À JOUR: Je viens de réaliser que je pouvais réimplémentez nouvel opérateur et l'opérateur supprimer les baseclass des objets retournés par les plug-ins, de sorte que les new'ing et les delete'ing entraînera toujours des appels de fonction dans la même module (de sorte que toutes les allocations et les libres soient faites dans le plugin, ou dans le framework).

Répondre

3

Il existe deux solutions. La solution 1 est "partager plus" - vous pouvez déplacer les nouvelles/supprimer sur les limites de la DLL si les deux côtés utilisent la même DLL CRT (/ MD ou/MDD dans MSVC). La solution deux est «partager moins» - laissez chaque DLL avoir son propre tas C++, et ne pas diviser nouveau/supprimer à travers les limites de la DLL.

2

Si le code DLL est responsable de l'allocation d'objets, il devrait également être responsable de les libérer. Je pense que votre problème est plus avec le comptage de référence et le "supprimer ceci". Si vous voulez suivre cette route, pourquoi ne pas simplement implémenter les objets en tant qu'objets COM? C'est après tout l'un des principaux problèmes que COM a été conçu pour résoudre!

4

Il s'est avéré que la façon la plus simple de s'assurer que la mémoire n'est pas allouée dans une DLL est: réimplément operator new et operator delete sur la classe de base des objets renvoyés par les plugins. Dans les implémentations de ces fonctions, appelez les fonctions 'alloc' et 'free' (qui ont été transmises depuis l'application principale lors du chargement du plugin). De cette façon, les plugins peuvent continuer à utiliser 'new' et 'delete' mais la mémoire sera réellement allouée et libérée dans l'application principale.

+0

Si vous réimplémentez les opérateurs nouveaux et supprimés des classes de base, ils utiliseront votre mémoire, mais qu'en est-il des allocations effectuées dans ces classes? Si le fournisseur de plugin ajoute un membre de chaîne, il sera alloué dans la DLL. Mais si vous supprimez l'objet de votre côté, la chaîne sera également détruite de votre côté, n'est-ce pas? Je vote pour fournir des fonctions globales obj * Create() et Destroy (obj *) ou AddRef() et Release(). Cela semble beaucoup plus sûr pour moi. – eran

+0

@eran Je me rends compte que ce commentaire a environ 3,5 ans de retard, mais je ne suis pas sûr de comprendre votre inquiétude.Si je redéfinis 'operator new' et' operator delete' sur la classe de base, ces opérateurs seront également utilisés s'ils sont utilisés depuis des classes dérivées. Voir par exemple http://ideone.com/cdNZMp qui montre deux appels aux implémentations 'new' /' delete' personnalisées, dont une paire est causée par 'return new Derived;' dans 'Derived :: f'. –

+0

Votre exemple de code crée une instance de la classe dont 'operator new' est réimplémenté, donc vous êtes couvert de toute façon. Je pense que ma préoccupation était une classe dérivée ayant un champ qui utilise le 'new' par défaut. Cette classe «nouveau» n'est pas couverte par votre placement. Cependant, maintenant que je lis à nouveau, je pense que j'avais tort. Toute la gestion de la mémoire à l'intérieur de la classe est sûre, tant que ce qui a été créé par la classe de base a été détruit par la classe de base, et ce qui a été créé par la classe dérivée est détruit par la classe dérivée. – eran