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

C++ Discussion :

Exportation de variable statique


Sujet :

C++

  1. #1
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut Exportation de variable statique
    Bonjour

    J'ai créé dans une DLL une classe singleton, exportée via la directive __declspec(dllexport). J'utilise pour créer mes singletons une classe de base template comme ceci :

    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 <class T>
    class CSingleton
    {
    public :
     
        static T& Instance();
     
        // ...
     
    private :
     
        static T* Inst;
     
        // ...
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class EXPORT MaClasse : public CSingleton<MaClasse>
    {
        friend class CSingleton<MaClasse>;
     
        // ...
    };
     
    // Puis dans MaClasse.cpp :
    template <> MaClasse* CSingleton<MaClasse>::Inst = NULL;
    Puis dans le programme utilisant la DLL, je manipule mon singleton normalement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaClasse::Instance().xxx();
    Ce code compile parfaitement sous Visual C++ 7.1, mais Dev-C++ 4.9.9.1 (gcc 3.3.1) me donne lui une erreur d'édition de lien en compilant le client de la DLL : il ne trouve pas MaClasse::Inst (qui est pourtant défini dans un .cpp et exporté comme toute sa classe). La DLL compile elle parfaitement avec les deux compilos.

    Est-ce que j'ai loupé quelque chose, fait une fausse manip (notamment avec le template singleton) ou bien est-ce un comportement maladroit de Dev-C++ ?

    Merci

  2. #2
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 82
    Points : 68
    Points
    68
    Par défaut
    On peut voir l'output de compilation ?

    Tu pourrais essayer de rajouter les flags --enable-auto-import et --enable-runtime-pseudo-reloc à l'édition de liens pour voir si ça marche mieux.

  3. #3
    sas
    sas est déconnecté
    Membre éprouvé

    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 54
    Points : 1 257
    Points
    1 257
    Par défaut
    l'erreur doit venir des options du projet....

    j'ai compilé la dll et l'exécutable sans problème sous dev-c++ 4.9.9.2

    voici le contenu de la dll :

    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
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
     
    // fichier singleton
     
    #include <cstdlib>
     
    template <typename T> class CSingleton
    {
    protected:
     
        CSingleton() { }
        ~CSingleton() { }
     
    public:
     
        static T* getInstance()
        {
            if( _M_inst == NULL )
            {
                _M_inst = new T;
            }
     
            return ((T*)_M_inst);
        }
     
        static void kill( void )
        {
            if( _M_inst != NULL )
            {
                delete _M_inst;
                _M_inst = NULL;
            }
        }
     
    private:
     
        static T *_M_inst;
    };
     
    template <typename T> T *CSingleton<T>::_M_inst = NULL;
     
    // fichier dll.h
     
    #ifndef _DLL_H_
    #define _DLL_H_
     
    #if BUILDING_DLL
    # define DLLIMPORT __declspec (dllexport)
    #else /* Not BUILDING_DLL */
    # define DLLIMPORT __declspec (dllimport)
    #endif /* Not BUILDING_DLL */
     
    #include "singleton"
     
    class DLLIMPORT DllClass : public CSingleton<DllClass>
    {
        friend class CSingleton<DllClass>; 
     
    private:
     
        DllClass();
        ~DllClass();
     
    public:
    	void	SetValue(int iValue);
    	int	 GetValue();
     
     
    private:
    	int	m_iValue;
    };
     
    template <> DllClass* CSingleton<DllClass>::_M_inst = NULL;
     
    #endif /* _DLL_H_ */
     
     
    // fichier dll.cpp 
     
    #include "dll.h"
    #include <windows.h>
     
    DllClass::DllClass() : m_iValue(0) { }
     
    DllClass::~DllClass() { }
     
    void
    DllClass::SetValue(int iValue)
    { 
        m_iValue = iValue;
    }
     
    int
    DllClass::GetValue()
    {
         return m_iValue;
    }
     
    BOOL APIENTRY DllMain (HINSTANCE hInst     /* Library instance handle. */ ,
                           DWORD reason        /* Reason this function is being called. */ ,
                           LPVOID reserved     /* Not used. */ )
    {
        switch (reason)
        {
          case DLL_PROCESS_ATTACH:
            break;
     
          case DLL_PROCESS_DETACH:
            break;
     
          case DLL_THREAD_ATTACH:
            break;
     
          case DLL_THREAD_DETACH:
            break;
        }
     
        /* Returns TRUE on success, FALSE on failure */
        return TRUE;
    }
    et pour le code 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
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    #include <cstdlib>
    #include <iostream>
     
    #include "dll.h"
     
    using namespace std;
     
    int main( int argc, char *argv[] )
    {
        DllClass *pClassDll1, *pClassDll2;
     
        pClassDll1 = DllClass::getInstance();
        pClassDll2 = DllClass::getInstance();
     
        pClassDll1->SetValue( 6 );
     
        cout << "pClassDll1::m_iValue = " << pClassDll1->GetValue() << endl;
        cout << "pClassDll2::m_iValue = " << pClassDll2->GetValue() << endl;
     
        DllClass::kill();
     
        system("PAUSE");
     
        return 0;
    }
    avec ta méthode d'initialisation du membre static Inst à partir de DllClass,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template <> MaClasse* CSingleton<MaClasse>::Inst = NULL;
    ça marche aussi par contre voit pas trop l'intérêt si c'est pour l'écrire dans toutes les classes singleton ??

  4. #4
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    En ce qui concerne ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    template <typename T> T *CSingleton<T>::_M_inst = NULL;
    J'ai cru naïvement que cela fonctionnait, mais le fait est que cela me créait deux instances différentes : une dans la DLL, et une autre dans le client. D'où l'instanciation "spécialisée" pour chaque classe.

    Sinon merci pour les réponses, je n'étais pas chez moi ce week-end mais je regarderai les options de mon projet demain et je vous tiendrai au courant.

  5. #5
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Citation Envoyé par dabeuliou
    Tu pourrais essayer de rajouter les flags --enable-auto-import et --enable-runtime-pseudo-reloc à l'édition de liens pour voir si ça marche mieux.
    Aucune changement

    Citation Envoyé par sas
    j'ai compilé la dll et l'exécutable sans problème sous dev-c++ 4.9.9.2
    Je n'avais pas vu que tu avais défini ta variable statique dans l'en-tête. Dans ce cas effectivement ça marche (puisqu'en incluant l'en-tête, le client définit lui aussi son instance statique), mais ça pose des problèmes comme je l'ai indiqué dans mon post précédent.

  6. #6
    sas
    sas est déconnecté
    Membre éprouvé

    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 54
    Points : 1 257
    Points
    1 257
    Par défaut
    Citation Envoyé par Loulou24
    Je n'avais pas vu que tu avais défini ta variable statique dans l'en-tête.
    oups, il y a une erreur dans mon code, il faut commenter l'une des deux méthodes de définition de la variable _M_inst, je ne l'ai pas compilé avec les deux méthodes défini en même temps.

    donc ça devrait fonctionner maintenant même avec ta méthode ???

  7. #7
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    oups, il y a une erreur dans mon code, il faut commenter l'une des deux méthodes de définition de la variable _M_inst, je ne l'ai pas compilé avec les deux méthodes défini en même temps.
    Oui j'avais deviné mais toujours est-il que quelque soit la définition utilisée, celle-ci se trouve dans un en-tête et non dans une unité de traduction comme elle devrait l'être.

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 82
    Points : 68
    Points
    68
    Par défaut
    S'il n'est pas trop long, tu pourrais nous coller l'output de compilation/édition de liens qui plante ?

  9. #9
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Compilateur: Default compiler
    Building Makefile: "E:\Programmes\C++\YesEngine\Tutos\moteur_partie7_src\Demo\Projects\DevCpp_4.9.9.1\Makefile.win"
    Finding dependencies for file: E:\Programmes\C++\YesEngine\Tutos\moteur_partie7_src\Demo\Projects\DevCpp_4.9.9.1\..\..\Sources\Main.cpp
    Finding dependencies for file: E:\Programmes\C++\YesEngine\Tutos\moteur_partie7_src\Demo\Projects\DevCpp_4.9.9.1\..\..\Sources\MyApplication.cpp
    Finding dependencies for file: E:\Programmes\C++\YesEngine\Tutos\moteur_partie7_src\Demo\Projects\DevCpp_4.9.9.1\..\..\Sources\MyConsole.cpp
    Finding dependencies for file: E:\Programmes\C++\YesEngine\Tutos\moteur_partie7_src\Demo\Projects\DevCpp_4.9.9.1\..\..\Sources\Terrain.cpp
    Exécution de make...
    make.exe -f "E:\Programmes\C++\YesEngine\Tutos\moteur_partie7_src\Demo\Projects\DevCpp_4.9.9.1\Makefile.win" all
    g++.exe ../../../Temp/demo/Main.o ../../../Temp/demo/MyApplication.o ../../../Temp/demo/MyConsole.o ../../../Temp/demo/Terrain.o -o "..\..\..\Bin\Demo.exe" -L"D:/Dev-Cpp/lib" -L"E:/Programmes/C++/Utils/Lib" -mwindows ../../../Bin/libYesEngine.a -mthreads -s

    ../../../Temp/demo/MyConsole.o(.text+0x96b):MyConsole.cpp: undefined reference to `Yes::CSingleton<Yes::CConsole>::Inst'
    ../../../Temp/demo/MyConsole.o(.text+0x9bc):MyConsole.cpp: undefined reference to `Yes::CSingleton<Yes::CConsole>::Inst'
    ../../../Temp/demo/MyConsole.o(.text+0x9c2):MyConsole.cpp: undefined reference to `Yes::CSingleton<Yes::CConsole>::Inst'
    ../../../Temp/demo/MyConsole.o(.text+0xb0f):MyConsole.cpp: undefined reference to `Yes::CSingleton<Yes::CConsole>::Inst'
    ../../../Temp/demo/MyConsole.o(.text+0xb60):MyConsole.cpp: undefined reference to `Yes::CSingleton<Yes::CConsole>::Inst'
    ../../../Temp/demo/MyConsole.o(.text+0xb66):MyConsole.cpp: more undefined references to `Yes::CSingleton<Yes::CConsole>::Inst' follow

    make.exe: *** [../../../Bin/Demo.exe] Error 1

    Exécution terminée

  10. #10
    sas
    sas est déconnecté
    Membre éprouvé

    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 54
    Points : 1 257
    Points
    1 257
    Par défaut
    autant pour moi, j'avais mal saisi le problème, j'ai defini la variable dans le corps du cpp de la dll, et les même erreurs sont apparus, bizarre....

    par contre, si tu n'as pas vraiment besoin d'une bibliothèque dynamique, tu peux toujours la compiler en statique pour ne plus avoir ce bug

  11. #11
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    par contre, si tu n'as pas vraiment besoin d'une bibliothèque dynamique, tu peux toujours la compiler en statique pour ne plus avoir ce bug
    C'est malheureusement impossible.

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 82
    Points : 68
    Points
    68
    Par défaut
    Bon, l'output cause pas des masses.

    Maintenant quand je relis ton premier post :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template <> MaClasse* CSingleton<MaClasse>::Inst = NULL;
    Pourquoi on initialise le membre statique comme ça et non par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MaClasse* MaClasse::Inst = NULL;
    ?
    T'as essayé cette solution ?
    Si ça se trouve, ce que je viens d'écrire est une horreur, je m'en excuse à l'avance ...

  13. #13
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    On ne peut pas initialiser un membre statique via une classe dérivée. Or Inst appartient à CSingleton<MaClasse>, et non directement à MaClasse.

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 82
    Points : 68
    Points
    68
    Par défaut
    En effet, j'ai fait un test et c'est ce que m'a dit gcc ...
    Pour info, j'ai réussi à compiler un code semblable au tiens dans mon projet avec gcc sous linux. Je n'ai pas encore testé sous windows.

  15. #15
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    J'ai finalement résolu le problème en me plongeant dans les sources du moteur 3D Ogre (qui utilise un système similaire). Il apparaît qu'il faut redéfinir (et masquer) la fonction Instance() dans chaque singleton dérivé, je n'ai pas tout compris de leur explication mais ça parle de compiler CSingleton<T>::Instance uniquement dans T.cpp au lieu de chaque .cpp qui l'inclue. Ainsi on évite bien l'erreur d'édition de lien.

    Merci à tous pour votre aide.

  16. #16
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 751
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 751
    Points : 10 667
    Points
    10 667
    Billets dans le blog
    3
    Par défaut
    Tu as un lien vers l'explication / le code final ?
    Si tu redéfinit instance dans la classe dérivé, elle sert à quoi la classe CSingleton ?

  17. #17
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Tu as un lien vers l'explication / le code final ?
    L'explication et le code final peuvent être trouvées dans la doc en ligne de Ogre, par exemple ici

    http://www.ogre3d.org/docs/api/html/classOgre_1_1ArchiveManager.html#Ogre_1_1ArchiveManagere1

    Override standard Singleton retrieval.

    Remarks:
    Why do we do this? Well, it's because the Singleton implementation is in a .h file, which means it gets compiled into anybody who includes it. This is needed for the Singleton template to work, but we actually only want it compiled into the implementation of the class based on the Singleton, not all of them. If we don't change this, we get link errors when trying to use the Singleton-based class from an outside dll.

    This method just delegates to the template version anyway, but the implementation stays in this single compilation unit, preventing link errors.
    Si tu redéfinit instance dans la classe dérivé, elle sert à quoi la classe CSingleton ?
    C'est la question que je me suis posée . Mais en fait on y gagne toujours un peu, puisqu'on factorise tout de même l'interdiction de la copie, et la destruction / création de l'instance. Tout ce qu'il reste à faire dans la classe dérivée c'est redéfinir une fonction Instance() qui appelle celle de la classe mère (ça se fait très bien avec une macro ). C'est sûrement pas la meilleure solution, mais pour le moment ça me convient très bien.

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

Discussions similaires

  1. [Tableaux] Probleme variable statique dans une classe
    Par Joe Le Mort dans le forum Langage
    Réponses: 7
    Dernier message: 31/08/2006, 11h35
  2. Utilisation d'une variable statique
    Par kurkaine dans le forum C++Builder
    Réponses: 6
    Dernier message: 14/06/2006, 13h49
  3. Problème d'export de variable
    Par in dans le forum Linux
    Réponses: 6
    Dernier message: 29/05/2006, 16h41
  4. Exporter une variable via un script sous KSH
    Par Snivel dans le forum Linux
    Réponses: 4
    Dernier message: 09/12/2005, 16h44
  5. Réponses: 3
    Dernier message: 23/02/2005, 14h34

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