IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Visual C++ Discussion :

DLL Multiple et singletons


Sujet :

Visual C++

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juin 2006
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Juin 2006
    Messages : 122
    Points : 59
    Points
    59
    Par défaut DLL Multiple et singletons
    Hello.

    Je continus de travailler sur un jeu perso, et pour bien faire, j'ai partage le jeu en deux DLL :

    - une DLL Engine, qui contient le moteur de jeu, donc ce qui permet de gerer l'affichage, le son, les scene du jeu, le gameplay, etc.

    - une DLL Data, qui contient les donnees propre au jeu, donc les game objects, les scenes, les menu, le tout code en C++.

    Mon probleme est le suivant :

    Dans la DLL Engine, j'ai declare une Factory, qui est un singleton avec une map<std::string, GameObject *>, qui stock des prototype des gameObject pour etre ensuite clones.

    Elle dispose d'une fonction Register, pour inserer les prototypes, et une fonction Create pour les cloner.

    Le EX_API contient le __cdecl

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class EX_API GameObjectFactory : public Singleton<GameObjectFactory>
    {
    	friend class Singleton<GameObjectFactory>;
    public:
    	GameObjectFactory();
    	~GameObjectFactory();
     
    	GameObject * Register(const std::string & name, GameObject * obj);
     
    	GameObject * Create(const std::string & name);
     
    private:
    	boost::unordered_map<std::string, GameObject *> m_prototypes;
    };
    Dans ma deuxieme DLL, j'ai une classe BasicEnemy, qui me sert pour tester la factory. Elle ne fait rien de plus qu'un GameObject, sinon overload la fonction Clone().

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class EX_API BasicEnemy : public GameObject
    {
    public:
    	BasicEnemy();
    	virtual ~BasicEnemy();
     
    	virtual GameObject * Clone() const;
    };
    Mon soucis est le suivant :
    Pour que mes prototype s'enregistre automatiquement, j'ai fait une macro REGISTER_GAMEOBJECT, comme suis :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define REGISTER_GAMEOBJECT(className) static GameObject * s_##className##decl = GameObjectFactory::Instance().Register(#className, new className());
    Et j'appel cette macro dans le fichier BasicEnemy.cpp, dans l'espace global
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <ExcellenceObjects/Enemies/BasicEnemy.hpp>
    #include <ExEngine/Gameplay/GameObjectFactory.hpp>
     
    namespace ex
    {
    REGISTER_GAMEOBJECT(BasicEnemy)
     
    BasicEnemy::BasicEnemy()
    {
    }
    ...
    Enfin, je fais un projet Win32 window, dans lequel je ne fais... rien. Juste un int main().

    L'erreur est la suivante : A l'execution, j'obtiens un crash sur la fonction register de mon GameObjectFactory, donc lorsque j'appel la macro REGISTER_GAMEOBJECT depuis ma DLL Data.
    Les Locals me disent que ma map n'a pas ete instanciee alors que la fonction a bien ete appelee.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    +		this	0x00000000 {size_=??? mlf_=??? cached_begin_bucket_=??? ...}	const boost::unordered_detail::hash_table<boost::unordered_detail::map<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,boost::hash<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::equal_to<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,ex::GameObject *> > > > * const
    +		k	"BasicEnemy"	const std::basic_string<char,std::char_traits<char>,std::allocator<char> > &
    +		bucket	0xcccccccc {next_=??? }	boost::unordered_detail::hash_bucket<std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,ex::GameObject *> > > *
    +		it	0xcccccccc {next_=??? }	boost::unordered_detail::hash_bucket<std::allocator<std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const ,ex::GameObject *> > > *
    Le "this" correspond a ma factory.

    Et c'est la que je ne comprend pas.
    J'ai essaye de declarer mon Basic Object directement dans la DLL Engine, et ca marche.

    Comment faire pour que ma Factory soit bien instanciee depuis ma DLL Data lorsque j'en ai besoin?

  2. #2
    Membre du Club
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juin 2006
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Juin 2006
    Messages : 122
    Points : 59
    Points
    59
    Par défaut
    J'ai pu trouver en fouillant sur Google :

    De ce que j'ai retenu, chaque DLL utilise son espace mémoire propre. Il n'existe donc pas 1 mais autant d'espace global qu'il y a de DLL. De fait, un singleton déclaré par template (Singleton<MyManager>) sera instancié autant de fois qu'il y a de DLL.

    La solution pour éviter ce problème est de faire comme ca :

    Dans le .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class EX_API GameObjectFactory : public Singleton<GameObjectFactory>
    {
    	friend class Singleton<GameObjectFactory>;
    public:
    	GameObjectFactory();
    	~GameObjectFactory();
     
    	static GameObjectFactory & Instance(); // La classe surcharge la fonction pour recuperer son instance (Ou en defini une autre)
     
    	GameObject * Register(const std::string & name, GameObject * obj);
     
    	GameObject * Create(const std::string & name);
     
    private:
    	boost::unordered_map<std::string, GameObject *> m_prototypes;
    };
    Dans le .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    GameObjectFactory & GameObjectFactory::Instance()
    {
    	return Singleton<GameObjectFactory>::Instance();
    }
    De cette maniere, l'instance du singleton renvoyée sera l'instance de la DLL dans laquelle il est déclaré et défini.

    Il fallait le savoir.

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 200
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 200
    Points : 12 354
    Points
    12 354
    Par défaut
    Absolument n'importe quoi de A à Z.

    Primo, découper une application monolithique sous forme de DLLs, c'est bien mais le précepte de base d'une bonne Dll, c'est de pouvoir l'utiliser dans un autre programme et avec d'autres Dlls.

    En partageant une API C++ avec des classes entre les Dll, vous êtes obligé :
    - Soit d'utiliser les 2 Dll en même temps parce que vous n'avez pas "leveliser" les API, vous avez par exemple besoin des classes de l'une pour exécuter les méthodes des classes l'autre Dll.
    - En utilisant un export de classe C++ vous obligez les utilisateurs de vos Dll a avoir, le même compilateur, la même version de compilateur, et en plus, les même options de compilations.

    En clair c'est complètement pourri l'export de classe C++. Faites des exports de fonction libre C.


    Secundo, votre implémentation fait un gros usage de variables globales, et il est impossible, en C++, de contrôler l'ordre d'initialisation des variables globales, d'où votre pointeur this à null. (à confirmer par votre implémentation du Design Pattern Singleton dont vous ne fournissez même pas le code dans votre premier post. )

    De ce que j'ai retenu, chaque DLL utilise son espace mémoire propre.
    MDR, ce n’est pas les Dll qui ont chacune leur espace mémoire, c'est le processus.
    Donc toutes les Dll chargées dans un processus partage le même espace mémoire.

    Vous confondez l'espace d'adressage mémoire et la résolution des noms lors de l'édition de lien des Dll.

    Pour faire un singleton à base de template, il faut quand même un peu maitriser ce qu'est un template.

    Vous pouvez avoir autant de Singleton<GameObjectFactory> que vous désirez dans une seule Dll, il suffit de changer le namespace englobant de #include du template ou en code de mettre un #define GameObjectFactory différent dans chaque cpp avant ce même #include.

    Enfin, un découpage en Dlls qui vous oblige à utiliser toutes les Dll et un Singleton qui n'est pas unique, c'est vraiment ni fait ni à faire.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. multiple rows singleton
    Par medkyl dans le forum Langage SQL
    Réponses: 7
    Dernier message: 17/11/2010, 01h06
  2. Réponses: 3
    Dernier message: 11/05/2010, 17h00
  3. [C++] DLL Multiples instances
    Par ouquoi dans le forum C++
    Réponses: 2
    Dernier message: 18/07/2006, 17h25
  4. pb : multiple rows in singleton select
    Par sillycoder dans le forum SQL
    Réponses: 6
    Dernier message: 12/06/2005, 17h35
  5. Réponses: 3
    Dernier message: 25/01/2005, 13h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo