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 :

Initialisation des instances de classe global


Sujet :

Langage C++

  1. #1
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut Initialisation des instances de classe global
    Bonjour.

    J'ai un .cpp qui encapsule une map global et 2-3 fonctions qui la manipule :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    namespace
    {
          std::map<std::string,int  > maMap;
     
    }
     
    void addElement(const std::string &name, int i)
    {
    	maMap[name] = i;
    }
    Dans d'autre fichier cpp la fonction addElement est appelé lors de l'initialisation d'une variable global de cette manière
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    namespace
    {
    	bool Init()
    	{
    		addElement("test",10);
    		return true;
    	}
    	bool initialized = Init();
    }
    seulement ça crash. C'est comme si la map n'était pas encore initialisée. Si j'utilise un pointeur ça fonctionne.

    J'ai du mal à comprendre pourquoi. Es ce que l'appel au constructeur des objets globaux se fait après l'initialisation des variables globales POD?

    En gros ce que je veux faire :
    1- j'ai une map qui représente un singleton.
    2- j'ai une fonction qui permet d'enregistrer une information dans cette map.
    3- l'enregistrement de cette information doit être faite qu'une seule fois.

    le deuxième bout de code est il correcte? je fait de temps en temps cela quand je doit initialiser des chose global. Comme par exemple une fonction d'initialisation d'un framework. J'utilise un bouleen global qui est initialisé par l'appel d'une fonction. Cette fonction va ainsi initialiser les partie globales.


  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 118
    Par défaut
    Peut être que je me trompe,

    mais un namespace n'est pas, me semble t'il, un bloc permettant l'exécution de code et donc à fortiori l'appel d'une fonction en l'occurence Init.

    [EDIT]Quoique ce code compile donc cela doit être valable. C'est en langage que ce type d'initialisation n'est pas autorisée.

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Tu as schématiquement 2 variables globales (ta map, et ton booléen). Tu les initialize dans deux fichiers cpp séparés.

    Rien n'indique dans quel sens les deux seront construits (alors que dans un même fichier, les variables globales sont construites dans leur ordre d'apparition). Tu te trouves là certainement à avoir le booléen qui est construit alors que la map ne l'a pas encore été => BOOM !

    Il y a une astuce pour t'assurer que ça puisse quand même marcher (recherche nifty counter pour plus d'infos), mais c'est très bas niveau, et il faut faire attention à des histoires d'alignement, de placement new,...

    Une solution plus simple est de faire de ta map un objet qui n'est plus global. Par exemple, si tu en fais une variable statique à l'intérieur d'une fonction, tu as la garantie qu'elle sera initialisée au premier appel de la fonction (en C++11, tu as même la garantie que ça se passe bien en multithread aussi, mais certains compilos n'implémentent toujours pas ça (donc Visual C++), te forçant pour avoir l'équivalent à définir un singleton avec lock sur la variable...)

    Voici la version C++11:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    std::map<std::string,int  > &getMap()
    {
      static std::map<std::string,int  > maMap;
      return maMap;
    }
    Mais une meilleure solution réside probablement par la suppression de ces variables globales
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Salut,
    Citation Envoyé par JolyLoic Voir le message
    Mais une meilleure solution réside probablement par la suppression de ces variables globales
    voire, de regrouper au minimum l'implémentation de l'ensemble au sein d'un seul et même fichier *.cpp, même si les déclarations des fonctions peuvent, en l'occurrence, être séparées
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Merci JolyLoic.
    C'est bien ce que je pensais. Ce qui m'étonne c'est si je remplacer le bout de code par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    namespace
    {
          std::map<std::string,int  > * maMap = NULL;
     
    }
     
    void addElement(const std::string &name, int i)
    {
            if(maMap  == NULL)
                maMap  = new std::map<std::string,int  >();
    	maMap[name] = i;
    }
    maMap était bien mis à NULL. Mais c'est peut être un coup de chance.

    Ta solution est celle que j'avais implémenté au final.

    Sinon, je ne veux pas regrouper un minimum car c'est justement pour bien séparer les dépendances que je voulais faire cela. Et fait j'ai une interface, et chaque implémentation de cette interface encapsule un framework. Et je veux pouvoir facilement enlever un framework.
    Pour être plus précis, ma map sert de factory light. C'est une map de std::fonction; Et la classes'enregistre à la factory par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    namespace
    {
    	bool Init()
    	{
    		adduneClasse("Ma classe",[](){return new MaClass();});
    		return true;
    	}
    	bool initialized = Init()
    };

  6. #6
    screetch
    Invité(e)
    Par défaut
    un pointeur est un POD et les POD sont initialises avant tout
    std::map n'est pas un POD, c'est une instance de classe qui n'est valable qu'apres que le constructeur ait ete appele.
    si tu as un pointeur ca marche (ca reste cradoc).

  7. #7
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par screetch Voir le message
    (ca reste cradoc).
    Qu'es ce qui te semble cradoc?

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 146
    Billets dans le blog
    4
    Par défaut
    Le côté pointeur, qu'il faut faire attention à supprimer, ce qui ajoute encore une méthode à l'interface. Et l'ajout du test pour la première initialisation.
    Avec la solution du static, on ne se soucie pas de ce(s) "problème(s)"
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #9
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Le côté pointeur, qu'il faut faire attention à supprimer, ce qui ajoute encore une méthode à l'interface. Et l'ajout du test pour la première initialisation.
    Avec la solution du static, on ne se soucie pas de ce(s) "problème(s)"
    Ha oui ça, je suis d'accord ^^.

  10. #10
    screetch
    Invité(e)
    Par défaut
    Citation Envoyé par yan Voir le message
    Qu'es ce qui te semble cradoc?
    * un pointeur sur un objet a semantique de valeur
    * tu leakes un std::map
    * tu executes le if a chaque addElement
    * tu a resolus un probleme de l'architecture, mais tu ne t'es pas assure que ce genre de probleme ne pouvait pas arriver encore une fois (si tu utilises cout, par exemple, ou un logger... etc), en gros tu as gueri un symptome mais pas la maladie derriere.

  11. #11
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par screetch Voir le message
    * un pointeur sur un objet a semantique de valeur
    * tu leakes un std::map
    * tu executes le if a chaque addElement
    * tu a resolus un probleme de l'architecture, mais tu ne t'es pas assure que ce genre de probleme ne pouvait pas arriver encore une fois (si tu utilises cout, par exemple, ou un logger... etc), en gros tu as gueri un symptome mais pas la maladie derriere.
    c'est bien pour cela que je voulais comprendre ^^
    Merci pour les explications.

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

Discussions similaires

  1. [Flex4] Comment copier des instances de classes différentes ?
    Par tristoon dans le forum Flex
    Réponses: 3
    Dernier message: 26/01/2011, 11h31
  2. Créer des instances de classes EMF dans Eclipse avec une jolie IHM
    Par obernard dans le forum Eclipse Platform
    Réponses: 3
    Dernier message: 24/02/2009, 19h21
  3. Envoyer des instances de classes via TCP
    Par ZouBi dans le forum C++
    Réponses: 8
    Dernier message: 02/08/2008, 17h07
  4. Réponses: 6
    Dernier message: 23/02/2006, 20h23
  5. Conditions de destruction des instances de classes
    Par elvivo dans le forum Général Python
    Réponses: 4
    Dernier message: 29/12/2004, 17h16

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