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 :

La portée du static au sein de differents projets


Sujet :

Visual C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2007
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 73
    Par défaut La portée du static au sein de differents projets
    Bonjour à tous,

    Voila j'ai (venant de Java/C#) voulu faire un objet qui soit accessible partout dans mon code.
    Rien de plus logique pour moi donc de faire un header avec l'objet se terminant par:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static MonObjet MonInstanceObjet;
    Si bien que partout dans le code je pourrais faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #include "monobjet.h"
     
    MonInstanceObjet.WriteCoucou();
    Seulement j'ai découvert que le static en C++ provoque de très nombreuse instanciation. Je m'en suis rendu compte en affichant un petit texte de test avec le "cout" dans le constructeur.

    J'ai donc tout logiquement cherché sur le net et de lien en lien j'en suis venu à trouver ce site: http://www.parashift.com/c++-faq-lit...html#faq-10.12 qui parle de "static initialization order fiasco".

    J'ai donc mis mon static dans une fonction static:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     MonObjet& GetInstanceObjet()
     {
       static MonObjet* obj = new MonObjet();
       return *obj;
     }
    #define MonInstanceObjet GetInstanceObjet()
    et cette fois c'est mieux...
    Mais pas parfait, je suis encore étonné de trouver 3 instance faite (au lieu d'une vingtaine précédemment correspondant au nombre de fois où je l'utilise). Malheureusement ce n'est pas ce que je souhaite puisque je n'en veux qu'une !

    Après de méticuleuse recherche, j'ai trouvé ce qui pourrait être la solution:
    J'ai 3 projet qui l'utilise dans la solution. Mon premier projet dépend d'un second projet qui dépend lui-même d'un troisième (et l'objet se trouve dans le troisième).
    J'en conclut donc que Visual compile projet par projet et offre une portée du static au projet uniquement.

    D'où la question: comment faire pour que le static dans la méthode globable se propage au sein du code de la solution entière?

    Lucyberad.

    [EDIT: j'utilise VS2008 en projet non-managé]

  2. #2
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Février 2005
    Messages : 5 487
    Par défaut
    Vous êtes très loin de la solution.
    Il ne faut jamais instancier d'objet dans les .h.
    Il n'y pas de constructeur static en C++.
    Les globales, comme dans tous les langages, c'est mal.
    Vous essayez d'implémenter un Patern Singleton complètement unsafe.

    Je ne cautionne donc pas le code suivant : (et pas testé)

    Dans le .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class MonObjet
    {
    private :
    static MonObjet* s_Instance = null;
     
    public :
    static MonObjet& GetInstanceObjet();
    }
    Dans le cpp :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
    MonObjet& MonObjet::GetInstanceObjet()
    {
        if(s_Instance == null)
        {
            s_Instance = new MonObjet();
        }
        return *s_Instance ;
    }

  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
    Par défaut
    Bonjour,
    Il y a à la base une confusion sur static.
    En C++, une variable globale statique n'est pas partagée par tous les objets d'un projet mais reste confinée dans l'unité de compilation (le .obj) où elle est déclarée. Donc mettre un static dans un .h et en inclure le .h dans différents .cpp revient à créer autant d'instances de la variable.
    Le singleton te permet d'avoir effectivement une seule variable pour toute l'application :
    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
     
    class singleton
    {
    private :
    static singleton* m_instance;
     
    public :
    /**
    @pre m_instance!=0
    */
    static singleton& instance();
     
    /**
     @pre m_instance==0
     @post m_instance!=0
    */
    static void create();
     
    /**
     @pre m_instance!=0
     @post m_instance==0
    */
    static void release();
     
    private:
       // avec un constructeur privé, seul la classe singleton peut créer un objet.
       singleton();
     
       // ces deux méthodes sont déclarées mais non définies pour interdire
       // la copie de l'objet (cf <a href="http://cpp.developpez.com/faq/cpp/?page=copiables" target="_blank">F.A.Q.</a>)
       singleton(singleton const&);
       singleton&operator=(singleton const&);
    };
    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
    singleton* singleton::m_instance=0;
    singleton& singleton::instance()
    {
       return *m_instance;
    }
     
    void singleton::create()
    {
       m_instance = new singleton;
    }
     
    void singleton::release()
    {
       delete m_instance;
       m_instance = 0;
    }
    Pour éviter la duplication dans les différents projets de ta solution, un seul projet doit compiler la définition (le .cpp), les autres ne doivent avoir que la déclaration (le .h).

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Février 2007
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 73
    Par défaut
    "Les globales, comme dans tous les langages, c'est mal."
    Oui mais pourtant c'est très utile et quand c'est bien amené c'est pas une si grande erreur que ca (a mon gout)...
    Je pense à l'objet "Console" dans C#, "System.out" dans Java et "cout" dans C++... Ce sont des globales.
    Après avoir son modèle de donnée en globale, je pense comme toi, c'est un blasphème. Mais quand c'est de l'utilitaire comme l'accès à la sortie console, c'est tout a fait viable. Sinon j'attend qu'à m'instruire et qu'on m'explique ce qu'il y a de mal dans ces pratique que les principaux langages utilisent dans leurs implémentations.

    "Pour éviter la duplication dans les différents projets de ta solution, un seul projet doit compiler la définition (le .cpp), les autres ne doivent avoir que la déclaration (le .h)."
    Ce qui revient à tout mettre dans le même projet sous Visual ce qui surcharge rapidement... ou modifier le projet qui compile pour s'étendre aux autres en désactivant le compilo des autres ce qui n'est pas franchement intuitif et propre... je vais revoir mon modèle sur ce point, c'est mieux je pense et je peux me le permettre (à première vue).

    Merci des infos.

  5. #5
    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
    Par défaut
    Citation Envoyé par Lucyberad Voir le message
    Citation Envoyé par 3DArchi
    Pour éviter la duplication dans les différents projets de ta solution, un seul projet doit compiler la définition (le .cpp), les autres ne doivent avoir que la déclaration (le .h).
    Ce qui revient à tout mettre dans le même projet sous Visual ce qui surcharge rapidement... ou modifier le projet qui compile pour s'étendre aux autres en désactivant le compilo des autres ce qui n'est pas franchement intuitif et propre... je vais revoir mon modèle sur ce point, c'est mieux je pense et je peux me le permettre (à première vue).

    Merci des infos.
    En toute logique ta solution comporte un exécutable et plusieurs bibliothèques (DLL ou statiques). Une de ces bibliothèques 'fournit' le service défini par ton singleton. C'est cette bibliothèque qui doit compiler le .cpp. Les autres utilisateurs de cette bibliothèque, l'exécutable et/ou d'autres bibliothèques incluent le fichier .h et se lient avec le .lib pour bénéficier du code.
    J'avoue que je comprend mal ton exposé du problème et ta réponse. Peux-tu préciser brièvement ton contexte (les types de projets liés entre eux) et ce qui te chagrine ?

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Février 2007
    Messages
    73
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2007
    Messages : 73
    Par défaut
    J'ai 3 projets. Il en est bien sur 1 qui est l'exécutable.
    Les deux autres se dépendent mutuellement et pour se faire lien, ont un include l'un de l'autre. Le projet de l'exécutable les inclut tout les deux.
    C'est à dire que le premier projet fait un include des 2 .lib des deux autres projets. De plus, pour que les liens puissent se faire sur les .h, ce projet "executable" possède aussi comme propriété "Autres repertoires includes" 2 chemin vers la racine des deux autres projets.
    Les deux autres projets sont d'ailleurs en statique (pas de DLL donc).
    Mais comme ce sont 3 projet, le compilo de Visual passe 3 fois pour compiler séparément et assemble ensuite le tout. Je me demandait alors (en posant la question sur ce forum) s'il existait une option qui permet de dire aux deux autres projets d'être compilé AVEC le premier projet ou que le premier projet compile les deux autres avec lui. J'ai cherché avant, dans les options de visual et sur le net mais sans succès.

    Mon objet partagé est un objet qui permet la gestion d'un log et fonctionne à la manière d'un "cout". Je voulais mettre dans un tableau (vector) les differents log (qui sont composé de 3 données: "temps [timestamp] + severité [enum] + message [string]") pour pouvoir le filer en brut par mail lorsque une exception au sein du programme est levée et attrapée à l'aide d'un formulaire de rapport de bug. Mais je me suis vite rendu compte que mon tableau était totalement incomplet. De ce fonctionnement indésirable, j'ai traqué les différentes instances pour en comprendre que c'était une vingtaine d'instance qui étaient crées (et non pas une seule). J'ai donc découvert le "Static Fiasco" présenté sur le site que j'ai donné en lien dans mon précédent post, mais malgré la résolution donnée (qui est un singleton en fait) j'ai toujours 3 instance séparée... J'ai vite compris que c'était un problème de compilation par projet puisque un rajout d'un 4ème projet qui utilise cet objet rajoute 1 instance.

    Au final, je peux outrepasser cette contrainte comme un avantage, c'est à dire vraiment faire que 3 logs soit fait (avec 1 instance par projet), puis ensuite les envoyer tout les 3 par mail (en accédant à partir du premier projet, où le formulaire de soumission de bug se trouve, aux instances des deux autres par des fonctions se trouvant dans les deux autres qui retourne l'objet de log de leur projet).
    C'est fonctionnel, ca permet de séparer les trois, d'un coté ca ajoute en clarté par la séparation des 3 logs mais retire compréhension de la trame du temps (puisqu'il faut remettre dans l'ordre en fonction du temps attribué lors de l'ajout du log) donc je n'y perd pas vraiment ni ne gagne...

    Après, ca peux passer en séparé pour ce système, mais je pense que certains (et probablement moi plus tard) seront face au même problème sans y trouver de solution... donc s'il y en a une, c'est toujours bon à savoir...

Discussions similaires

  1. Réponses: 0
    Dernier message: 15/12/2010, 16h33
  2. Réponses: 2
    Dernier message: 13/12/2010, 12h14
  3. Réponses: 0
    Dernier message: 19/10/2009, 10h46
  4. portée variable static java entre 2 contextes
    Par c+cool dans le forum Tomcat et TomEE
    Réponses: 2
    Dernier message: 20/04/2009, 09h57
  5. Accessibilité d'un jar au sein d'un projet web
    Par T`lash dans le forum Glassfish et Payara
    Réponses: 1
    Dernier message: 08/03/2008, 07h44

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