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

Bibliothèques C++ Discussion :

[probleme] template singleton et .lib static


Sujet :

Bibliothèques C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 37
    Points : 28
    Points
    28
    Par défaut [probleme] template singleton et .lib static
    Bonjour,

    J'ai un probleme de context entre mon binaire et une lib statique _Et dynamique_ que j'ai fait.
    Je voulais savoir si quelqu'un a une solution.

    J'ai un template Singleton basique du genre :
    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
     
    template <typename T>
    class Singleton
    {
    public:
    static T& get(void);
    static void destroy(void);
     
    protected:
    Singleton(void);
    virtual ~Singleton(void);
     
    protected:
    static T *s_pInstance;
    };
    cela marche tres bien, mais le probleme intervient quand une class de ma lib static derive de ce template en lui donnant son propre type.
    ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class Foo : public Singleton<Foo>
    {
    friend class Singleton<Foo>;
    };
    Je crois que le compilo me cree deux classes (une pour mon binaire et une pour ma lib _statique_ dynamique) a la compil pour un meme type T.
    (logique vu que le template est dans le .h, utilise par la lib et le binaire a la compil)

    du coup, lorsque je fais un Foo::Get(), selon que je sois dans du code implemente dans mon binaire ou dans ma lib (dynamique), ce n'est en realite pas la meme classe qui est appele, du coup les s_pInstance sont logiquement different, et mon Singleton n'en est plus un ! et ca fou mechament le bordel.


    Si je n'ai plus de template, mais que je me paluche le Get Destroy static directement dans ma classe Foo, alors la pas de soucis, il n'y a bien qu'une classe et donc qu'une instance, mais j'ai besoin de ce template.

    --> en fait non, ca ne marche pas non plus.

    merci d'avance pour votre aide.

  2. #2
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    507
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Mai 2006
    Messages : 507
    Points : 705
    Points
    705
    Par défaut
    Bonjour,

    Je suis pas certains d'avoir compris ton problème, mais concernant les bibliothèques statiques, elles sont intégrées à chacun des binaires compiler.

    C'est-à-dire, si dans ton projet tu as une bibliothèque dynamique et un exécutable, et que les deux utilisent ta bibliothèque statique, alors cette dernière sera intégrée dans chacun des binaires. Donc si ta bibliothèque statique possède des variables statiques, alors tu auras deux fois les variables statiques...

  3. #3
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Pareil. Je ne suis pas sûr de comprendre ton problème. D'autant qu'une classe générique ne produit du code que lorsqu'elle est instanciée. Peux-tu préciser la structure de ton projet ?

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 37
    Points : 28
    Points
    28
    Par défaut
    Effectivement, je me suis bien emmelé dans mon explication, et j'ai melangé ma lib static et dynamique.

    le probleme ne viens d'ailleurs surment pas du fait du template, mais plustot de l'instance membre statique.


    mon binaire link bien vers une lib static qui contient le singleton, et la pas de soucis lors de son utilisation. Il link aussi vers une lib dynamic qui elle meme link aussi vers la lib static.

    Donc lorsque j'utilise Foo dans l'implementation de DynLib, il est different de celui instancié dans le binaire, du au fait comme vous le dite plus haut, qu' a la compil du binaire et de DynLib deux instances différentes sont crée.

    voila le petit exemple complet, avec le binaire, la lib statique et dynamique.
    Quelles solution(s) peut on trouver a ce genre de pb, sachant que j'aimerai conserver ma lib statique. N'y a t il pas moyen de faire en sorte que le singleton dans mes lib dynamique recupere l'instance de mon singleton instancié dans le binaire ?

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    /////////////////////////////////////////////////////////
    //////////////////////// BINAIRE ////////////////////////
     
    /**************** main.cpp ****************/
     
    #include "BinBar.h"
    #include "LibBar.h"
    #include "DynBar.h"
    #include "LibFoo.h"
     
    int main(int ac, char **av)
    {
    	BinBar a;
    	LibBar b;
    	DynBar c;
     
    	Foo::Get().Initialize();
     
    	a.Test(); // -> affiche 42, pas de soucis
    	b.Test(); // -> affiche 42, pas de soucis
    	c.Test(); // -> affiche -1, ce n'est effectivement pas le meme singleton, ce qui m'embete.
     
    	return 0;
    }
     
     
    /**************** BinBar.h ****************/
     
    class BinBar
    {
    public:
    	void Test(void);
    };
     
    /**************** BinBar.cpp ****************/
     
    #include "BinBar.h"
    #include "LibFoo.h"
     
    void BinBar::Test(void)
    {
    	Foo::Get().PrintValue();
    }
     
     
    /////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
     
    /////////////////////////////////////////////////////////
    ////////////////////// STATIC_LIB ///////////////////////
     
    /**************** Singleton.h ****************/
     
    #ifndef _LIB_SINGLETON_H_
    #define _LIB_SINGLETON_H_
     
    template <class T>
    class Singleton
    {
    public:
    	inline static T& Get(void)
    	{
    		if (!s_pInstance)
    			s_pInstance = new T();
     
    		return *s_pInstance;
    	};
     
    	inline static void Destroy(void)
    	{
    		delete s_pInstance;
    		s_pInstance = 0;
    	};
     
    protected:
    	Singleton(void){};
    	virtual ~Singleton(void){};
     
    protected:
    	static T *s_pInstance;
    };
     
    template <class T> T* Singleton<T>::s_pInstance = 0;
     
    #endif
     
     
     
    /**************** LibFoo.h ****************/
     
    #include "LibSingleton.h"
     
    class Foo : public Singleton<Foo>
    {
    	friend class Singleton<Foo>;
     
    public:
    	void Initialize(void);
    	void PrintValue(void);
     
    protected:
    	Foo(void);
    	virtual ~Foo(void);
     
    protected:
    	int m_iValue;
    };
     
    /**************** LibFoo.cpp ****************/
     
    #include "LibFoo.h"
    #include <iostream>
     
    Foo::Foo(void) : Singleton<Foo>()
    , m_iValue(-1)
    {
     
    }
     
    Foo::~Foo(void)
    {
     
    }
     
    void Foo::PrintValue(void)
    {
    	std::cout << "Value is : " << m_iValue << std::endl;
    }
     
    void Foo::Initialize(void)
    {
    	m_iValue = 42;
    }
     
    /**************** LibBar.h ****************/
     
    class LibBar
    {
    public:
    	void Test(void);
    };
     
    /**************** LibBar.cpp ****************/
     
    #include "LibBar.h"
    #include "LibFoo.h"
     
    void LibBar::Test(void)
    {
    	Foo::Get().PrintValue();
    }
     
    /////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////

    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
    33
    34
    35
    36
    37
    38
    39
     
    /////////////////////////////////////////////////////////
    //////////////////////// DYN_LIB ////////////////////////
     
    /**************** DynExport.h ****************/
     
    #ifndef _DYN_EXPORT_
    #define _DYN_EXPORT_
     
    #ifdef DYNAMICLIB_EXPORTS
    #define DYN_API __declspec(dllexport)
    #else
    #define DYN_API __declspec(dllimport)
    #endif
     
    #endif
     
    /**************** DynBar.h ****************/
     
    #include "DynExport.h"
     
    class DYN_API DynBar
    {
    public:
    	void Test(void);
    };
     
    /**************** DynBar.cpp ****************/
     
    #include "DynBar.h"
    #include "LibFoo.h"
     
    void DynBar::Test(void)
    {
    	Foo::Get().PrintValue();
    }
     
    /////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////

  5. #5
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    507
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Mai 2006
    Messages : 507
    Points : 705
    Points
    705
    Par défaut
    Citation Envoyé par typedef Voir le message
    Quelles solution(s) peut on trouver a ce genre de pb, sachant que j'aimerai conserver ma lib statique. N'y a t il pas moyen de faire en sorte que le singleton dans mes lib dynamique recupere l'instance de mon singleton instancié dans le binaire ?
    Je crains, que tu ne sois obligé de passer ta lib statique en dynamique...
    Sinon, il faut que tu fasses une sur-couche de ta classe dans une des lib dynamiques et que tu n'utilises dans tout ton projet que la surcouche...

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Fabllot Voir le message
    Je crains, que tu ne sois obligé de passer ta lib statique en dynamique...
    Sinon, il faut que tu fasses une sur-couche de ta classe dans une des lib dynamiques et que tu n'utilises dans tout ton projet que la surcouche...
    J'aurais tendance à dire la même chose.

  7. #7
    Membre régulier Avatar de thoratou
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 116
    Points
    116
    Par défaut
    A mon avis, ton problème est le problème classique de l'unicité d'un singleton avec une bibliothèque dynamique. Le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template <class T> T* Singleton<T>::s_pInstance = 0;
    est contenu dans le header de Singleton, ce qui fait que l'instance sera présente dans chaque lib/dll/exe qui utilise ton instance de Singleton.

    Une solution serait de compiler une fois pour tout le Singleton en mettant le code "Utile" singleton dans un .cpp et spécifier les differents types d'instances de ton Singleton.

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
     
    /**************** Singleton.h ****************/
     
    #ifndef _LIB_SINGLETON_H_
    #define _LIB_SINGLETON_H_
     
    template <class T>
    class Singleton
    {
    public:
    	inline static T& Get(void);
    	inline static void Destroy(void);
    protected:
    	Singleton(void);
    	virtual ~Singleton(void);
    protected:
    	static T *s_pInstance;
    };
     
    #endif
     
    /**************** Singleton.cpp ****************/
     
    #include <Singleton.h>
    #include <Foo.h>
     
    template <class T> T* Singleton<T>::s_pInstance = 0;
     
    template <class T>
    Singleton<T>::Singleton(void){}
    template <class T>
    Singleton<T>::~Singleton(void){}
     
    template <class T>
    static T& Singleton<T>::Get(void)
    {
    	if (!s_pInstance)
    		s_pInstance = new T();
     
    	return *s_pInstance;
    }
     
    template <class T>
    static void Singleton<T>::Destroy(void)
    {
    	delete s_pInstance;
    	s_pInstance = 0;
    }
     
    // le point important du code
    template class Singleton<Foo>;
    Ici l'instance n'est contenue que dans une seule lib mais utilisable par tout le monde.
    Désolé pour cette réponse tardive.

  8. #8
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Si tu veux être tranquille à tout point de vue, quel que soit le mode de compilation, d'utilisation et le nombre "d'instances" de ta librairie, ça m'étonnerait que tu puisses le faire en C++ "pur"... Car tu entres dans la problématique de l'unicité inter-processus. En effet, ton problème se situe, justement, dans le template : à la compilation, ton template va générer du code... Aussi bien dans l'exécutable que dans la DLL, et ce n'est pas "le même" code dans les deux !

    Tu auras, tacitement, le même problème avec ton singleton dans une DLL : si elle est utilisée par plusieurs processus, tu auras autant d'instances que de processus si tu ne fais rien pour avoir une unicité au niveau système.

    Le plus simple pour réaliser ton besoin est, en général, d'utiliser un bout de mémoire partagée et un mutex nommé (donc visibles depuis n'importe quel processus du système), et de stocker l'instance singleton dans ce bout de mémoire partagée. Par contre, ce n'est évidemment pas portable "comme ça", mais ça te permet d'avoir tout en template et en librairie statique sans être ennuyé. Si tu n'as PAS besoin d'une unicité au niveau système, mais uniquement au niveau processus, il te suffit de nommer la mémoire partagée et le mutex avec un pattern tenant compte du PID du processus (ce qui créera autant d'instances que de processus).

    En pratique, pour faire ça :
    • On détermine le nom des ressources partagées : soit de façon figée (unicité système), soit processus par processus (en intégrant le PID du processus dans le nom).
    • Si le mutex est pris, un singleton existe déjà. Sinon, il faut le créer.
    • Si le singleton existe, il suffit d'ouvrir la mémoire partagée et de récupérer l'adresse de la classe singleton.
    • Si aucune instance n'existe :
      • Tu instancies ton singleton.
      • Tu initialises la mémoire partagée et le mutex.
      • Tu copies l'instance en mémoire partagée.
      • Tu finis en prenant le mutex.
    • Dans tous les cas, tu sors avec un pointeur sur le singleton, qui peut bien sûr être un pointeur avec référence si tu veux un singleton auto-destructible.

    Cela marche très bien sous Windows, c'est un poil plus complexe sous Linux, mais dans les deux cas cela ne pose aucun problème particulier si tu connais un minimum ton OS au niveau système.

  9. #9
    Membre régulier Avatar de thoratou
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 116
    Points
    116
    Par défaut
    Si tu veux être tranquille à tout point de vue, quel que soit le mode de compilation, d'utilisation et le nombre "d'instances" de ta librairie, ça m'étonnerait que tu puisses le faire en C++ "pur"... Car tu entres dans la problématique de l'unicité inter-processus. En effet, ton problème se situe, justement, dans le template : à la compilation, ton template va générer du code... Aussi bien dans l'exécutable que dans la DLL, et ce n'est pas "le même" code dans les deux !

    Tu auras, tacitement, le même problème avec ton singleton dans une DLL : si elle est utilisée par plusieurs processus, tu auras autant d'instances que de processus si tu ne fais rien pour avoir une unicité au niveau système.
    Non justement l'exemple d'implémentation que je te montre permet d'avoir une instance partagee et non une recopie.

    Il y a deux fichiers :
    Singleton.cpp
    Singleton.hpp

    C'est le fichier Singleton.cpp qui contient l'instance du singleton. Ainsi il n'est compilé qu'une seule fois dans la Dll. Lors que les autres dll/exe voudront accéder au Singleton, ils iront chercher cette instance dans la dll.

    Ce qui permet ca c'est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template <class T> T* Singleton<T>::s_pInstance = 0;
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template class Singleton<Foo>;
    tous les 2 placés dans le .cpp

    Dans ce cas la, pas de copie de code, pas de copie d'instance.

    Par contre il y a un petit défaut a ce problème : Il faut ajouter autant de template class Singleton<XXX>; que de type de Singleton. Cela limite donc les types d'instance aux types présents dans la Dll.

  10. #10
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par thoratou Voir le message
    Non justement l'exemple d'implémentation que je te montre permet d'avoir une instance partagee et non une recopie.
    <snip>
    Par contre il y a un petit défaut a ce problème : Il faut ajouter autant de template class Singleton<XXX>; que de type de Singleton. Cela limite donc les types d'instance aux types présents dans la Dll.
    Cela ne marche qu'au sein d'un même processus, et comme tu le signales, c'est limité aux types compilés au niveau de la DLL... Ce qui réduit significativement l'intérêt du template, car il faut savoir à l'avance vers quoi le spécialiser, et ne permet pas de toutes façons d'avoir un singleton au niveau système (inter-processus).

  11. #11
    Membre régulier Avatar de thoratou
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 116
    Points
    116
    Par défaut
    Sauf qu'en attendant ca répond aux besoins de typedef sans pour autant s'embêter (pour être poli ) avec de la mémoire partagée.

  12. #12
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par thoratou Voir le message
    Sauf qu'en attendant ca répond aux besoins de typedef sans pour autant s'embêter (pour être poli ) avec de la mémoire partagée.
    Yep, mais t'es toujours obligé de spécialiser les templates au niveau de la DLL... Donc, de savoir à l'avance de quels singletons tu auras besoin dans le programme appelant, ce qui n'est (normalement) pas possible.
    OK, ça peut résoudre le problème ponctuel de l'OP, mais ce n'est pas une solution valable dans TOUS les cas, c'est surtout ça que je veux souligner.

    Après, on se fait un monde de la mémoire partagée, mais c'est bête comme tout à utiliser...

  13. #13
    Membre régulier Avatar de thoratou
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Points : 116
    Points
    116
    Par défaut
    en plus y'a boost qui nous vient en aide pour la memoire partagee, histoire de faire quelque chose de portable

Discussions similaires

  1. Template Singleton problem
    Par grigoux dans le forum Langage
    Réponses: 3
    Dernier message: 25/10/2009, 23h46
  2. probleme template hash_map
    Par rolphbrua dans le forum Langage
    Réponses: 1
    Dernier message: 08/08/2006, 23h18
  3. probleme template qcm en loadmovie
    Par serna dans le forum Flash
    Réponses: 3
    Dernier message: 05/06/2006, 22h59
  4. Probleme Template
    Par Muetdhiver dans le forum Langage
    Réponses: 11
    Dernier message: 18/04/2006, 11h00
  5. probleme template me renvoi qq chose en trop
    Par Triangle dans le forum XSL/XSLT/XPATH
    Réponses: 5
    Dernier message: 29/07/2005, 15h01

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