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

Langage C++ Discussion :

Singleton template partagé entre Dll et Exe


Sujet :

Langage C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 6
    Par défaut Singleton template partagé entre Dll et Exe
    Bonjour,
    J'ai un problème, qui dans sa version de base à déjà été écvoquer / partiellement résolu.
    Ce problème de base est :
    Comment partager l'instance d'un singleton entre une Dll et L'Exe si chaqun fait appel à getInstance dans son propre espace mémoire ?
    voici un exemple de code source correspondant à ce problème :
    Le template des singletons génériques :
    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #ifndef SINGLETON
    #define SINGLETON
    template <class S>
    class Singleton
    {
    private:
    static S * instance;
    //static S Instance;
    public:
    /*
      static S & Get ()
      {
    	 static S Instance; // règle le cas de l'ordre de construction
    						// mais pas celui de l'ordre de destruction
    	 return Instance;
      }
      */
      /**/
            static S * Get ()
            {
                    if(!instance)
                            instance = new S;
                    return instance;
            }
            /**/
    };
    //template <class S>
    //S Singleton<S>::Instance;
    template <class S>
    S* Singleton<S>::instance = 0;
     
    #endif
    le singleton qui en dérive et en instancie par la même occasion (si on peut parler d'instanciation de template) :
    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include <iostream>
     
    using namespace std;
     
    class TheSingleton
       : Singleton <TheSingleton> // magie!
    {
       // sans ceci, le parent ne peut instancier son enfant
    	friend class Singleton <TheSingleton>;
    	TheSingleton (): m_Cur (0)
    	{
    		cout<<endl<<"Nouveau Singleton !!!"<<endl<<endl;
    	};
     
    	~TheSingleton(){};
     
    	int m_Cur;
    public:
    	// vos services vont ici
    	int Prochain()
    	{
    		return ++m_Cur; 
    	};
     
    	//static TheSingleton * Get() {return Singleton<TheSingleton>::Get();}
    };
    #endif
    la classe principale de ma DLL exemple :
    .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
    17
    18
    #ifndef TESTSINGLETONDLL
    #define TESTSINGLETONDLL
    #include "TheSingleton.h"
    #include "dllImportExport.h"
    #include <iostream>
     
    using namespace std;
     
    class DECLSPECIFIER_DLL TestSingletonDll
    {
    public:
    	TestSingletonDll (){};	
     
    	~TestSingletonDll(){};	
     
    	int Next();
    };
    #endif
    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include "TestSingletonDll.h"
     
    int TestSingletonDll::Next()
    {
    	return Singleton<TheSingleton>::Get()->Prochain();
    	//return TheSingleton::Get()->Prochain();
    }
    la classe principale de mon executable :
    .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #ifndef TESTSINGLETONMAIN
    #define TESTSINGLETONMAIN
    #include "TestSingletonDll.h"
    #include <iostream>
     
    using namespace std;
     
    class TestSingletonMain   
    {   
    public:
    	TestSingletonMain(){};
    };
    #endif
    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include "TestSingletonMain.h"
    int main ()
    {
    	int ij;
    	TestSingletonMain* m = new TestSingletonMain();
    	TestSingletonDll* d = new TestSingletonDll();
    	cout << " courant : "<<d->Next()<<endl;
    	cout << " courant : "<<d->Next()<<endl;
    	cout<< " courant : "<<Singleton<TheSingleton>::Get()->Prochain()<<endl;
    	//cout<< " courant : "<<TheSingleton::Get()->Prochain()<<endl;
     
    	cin >> ij;
    }
    la sortie affichée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Nouveau Singleton !!!
     
     courant : 1
     courant : 2
     
    Nouveau Singleton !!!
     
     courant : 1
    Le problème ne semble donc pas résolu.

    Finalement en exportant l'instanciation du singleton ça marche effectivement :

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    using namespace std;
     
    //class TheSingleton;
    //EXPIMP_TEMPLATE_DLL template class DECLSPECIFIER_DLL Singleton<TheSingleton>;
     
    class DECLSPECIFIER_DLL TheSingleton
       : Singleton <TheSingleton> // magie!
    {
       // sans ceci, le parent ne peut instancier son enfant
    	friend class Singleton <TheSingleton>;
    	TheSingleton (): m_Cur (0)
    	{
    		cout<<endl<<"Nouveau Singleton !!!"<<endl<<endl;
    	};
     
    	~TheSingleton(){};
     
    	int m_Cur;
    public:
    	// vos services vont ici
    	int Prochain()
    	{
    		return ++m_Cur; 
    	};
     
    	//static TheSingleton * Get() {return Singleton<TheSingleton>::Get();}
    };
    #endif
    avec dllImportExport.h :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #ifndef DLLIMPORTEXPORT_H
    #define DLLIMPORTEXPORT_H
     
    //macro to define if we export (from a DLL) or Import (from the Exe) without changing the header
    #ifdef EXP_BLOCK // so we are in a DLL Block
    #    define DECLSPECIFIER_DLL __declspec(dllexport)
    #    define EXPIMP_TEMPLATE_DLL
    #else // so we are in the Exe
    #     define DECLSPECIFIER_DLL __declspec(dllimport)
    #     define EXPIMP_TEMPLATE_DLL extern
    #endif
    #endif
    Le problème de base est donc résolu.

    La où je viens ici, c'est que contrairement a ce que j'ai présenté ici,
    le problème est que dans ma véritable application, j'utilise des templates même en temps que singleton
    (attention a ne pas confondre au singleton générique de base qui est lui aussi un template).
    j'utilise quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template <class A,class B>
    class TheTemplatedSingleton
       : Singleton <TheTemplatedSingleton<A,B>> 
    {
        ... 
    }
    Pour l'instant je suis arrivé a une solution "médiane"
    Le problème que j'ai est que l'on ne peut pas vraiment exporter un template :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <class A, class B>
    class DECLSPECIFIER_DLL TheTemplatedSingleton
       : Singleton <TheTemplatedSingleton<A,B>> // magie!
    {
     ...
    }
    ça build bien la Dll, mais du point de vu de l'exe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include "TestSingletonMain.h"
    int main ()
    {
    	int ij;
    	TestSingletonMain* m = new TestSingletonMain();
    	TestSingletonDll* d = new TestSingletonDll();
    	cout << " courant : "<<d->Next<int,int>()<<endl;
    	cout << " courant : "<<d->Next<int,int>()<<endl;
    	//cout<< " courant : "<<Singleton<TheTemplatedSingleton<int,int>>::Get().Prochain()<<endl;
    	cout<< " courant : "<< TheTemplatedSingleton<int,int>::Get().Prochain() <<endl;
     
    	cin >> ij;
    }
    par contre le build ne finit pas, et débouche sur une erreur à l'étape de link :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    1>TestSingletonMain.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: static class TheTemplatedSingleton<int,int> & __cdecl TheTemplatedSingleton<int,int>::Get(void)" (__imp_?Get@?$TheTemplatedSingleton@HH@@SAAAV1@XZ) referenced in function _main
    1>TestSingletonMain.obj : error LNK2019: unresolved external symbol "public: int __thiscall TestSingletonDll::Next<int,int>(void)" (??$Next@HH@TestSingletonDll@@QAEHXZ) referenced in function _main
    bien sur si j'enlève les export/import :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <class A, class B>
    class /*DECLSPECIFIER_DLL*/ TheTemplatedSingleton
       : Singleton <TheTemplatedSingleton<A,B>> // magie!
    {
     ...
    }
    ça compile bien mais je me retrouve au problème initiale : duplication des instances :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
       Nouveau Singleton !!!
     
    courant : 1
    courant : 2
     
    Nouveau Singleton !!!
     
    courant : 1
    finallement je suis obliger de simuler l'exportation du template pour passer l'étape de link.
    Cela se fait en declarant et en exportant les différentes instance de template que l'on va utiliser :

    TheTemplatedSingleton.cpp:
    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
     
    #include "TheTemplatedSingleton.h"
    template <class A, class B>
    TheTemplatedSingleton<A,B>::TheTemplatedSingleton (): m_Cur (0)
    	{
    		cout<<endl<<"Nouveau Singleton<"<<typeid(A).name()<<","<<typeid(B).name()<< "> !!!"<<endl<<endl;
    	}
     
    template <class A, class B>
    int TheTemplatedSingleton<A,B>::Prochain()
    	{
    		return ++m_Cur; 
    	}
    EXPIMP_TEMPLATE_DLL template class DECLSPECIFIER_DLL TheTemplatedSingleton<int,int>;
    //EXPIMP_TEMPLATE_DLL template class DECLSPECIFIER_DLL Singleton<TheTemplatedSingleton<int,int>>;
    et

    TestSingletonDll.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #include "TestSingletonDll.h"
     
    template<class A, class B>
    int TestSingletonDll::Next()
    {
    	//return Singleton<TheTemplatedSingleton<A,B>>::Get().Prochain();
    	return TheTemplatedSingleton<A,B>::Get().Prochain();
    }
     
    EXPIMP_TEMPLATE_DLL template DECLSPECIFIER_DLL int TestSingletonDll::Next<int,int>();
    En ce cas je peut builder l'executable car celui-ci n'utilise que l'instance du singleton template :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TheTemplatedSingleton<int,int>
    que je viens d'exporter explicitement (cette instance de TheTemplatedSingleton pour les type <int,int>)

    et on peut voir que cela fonctionne effectivement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Nouveau Singleton<int,int> !!!
     
     courant : 1
     courant : 2
     courant : 3
    Donc content ?
    en fait NON car comme on le vois si on veut exporter un template, qui est singleton afin de n'avoir
    qu'une seul instance (par instance de template!) partager entre la (les) Dll et l'exécutable,
    il faut exporter explicitement TOUTES les instances possible du template que l'on serai a même d'utiliser au niveau de l'exécutable ...
    bref plutôt contraignant ...

    Existe t'il une solution/une parade a cela ? je suis preneur de toute information en ce sens

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Tu ne peux pas avoir de variable template partagée entre une DLL et un EXE.

    Par contre, tu peux avoir une variable partagée non-template (ou une instance spécifique d'un template) qui serait exportée par la DLL, et seulement cette DLL-là.

    Sinon, tu peux tenter un "singleton pour tout le process", mais pour l'instant je n'ai rien trouvé de plus économique que de jouer avec les File Mapping nommés pour ça...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. Partage d'une BDD entre web et exe
    Par wdmini dans le forum HyperFileSQL
    Réponses: 1
    Dernier message: 09/07/2012, 16h22
  2. partage de resx entre dll
    Par julien_iz dans le forum C#
    Réponses: 10
    Dernier message: 20/03/2009, 16h14
  3. DLL partagé entre deux programme
    Par CTotophe85 dans le forum C++
    Réponses: 22
    Dernier message: 26/09/2008, 14h00
  4. [TOMCAT] Partager une dll entre 2 webapp
    Par lucho31 dans le forum Tomcat et TomEE
    Réponses: 7
    Dernier message: 18/12/2005, 20h48

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