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 :

Fiasco dans l'ordre d'initialisation des variables statiques


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Inscrit en
    Août 2009
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 36
    Points : 36
    Points
    36
    Par défaut Fiasco dans l'ordre d'initialisation des variables statiques
    Bonjour à tous,

    J'ai quelques questions à poser par rapport à ce problème. J'ai déjà fait le tour des FAQ, mais je n'ai rien trouvé pour m'aider. J'ai bien compris que ce problème s'applique également au champs membres de mes classes.

    J'ai donc mis en place le mécanisme conseillé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Object& MyClass::o(){
        static Object *o = new Object();
        return *o;
    }
    Maintenant, j'ai une question, comme faire si je veux modifier ma variable statique ? Je ne peux pas accèder à o, contrairement à avant que je mette en place cette solution. Des idées ?

  2. #2
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    Bonjour.
    Citation Envoyé par la_urre Voir le message
    Maintenant, j'ai une question, comme faire si je veux modifier ma variable statique ? Je ne peux pas accèder à o, contrairement à avant que je mette en place cette solution. Des idées ?
    Que veux-tu dire : ici, pour accéder à o, il suffit d'appeler la méthode o de ta classe... et ce sera toujours la même instance .
    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
      Myclass My;
      My.o=Unautreobjet;
      std::cout<<My.o==Unautreobjet<<std::endl;
      //doit affficher 1 (ou true, je sais plus comment se comporte le cin avec les booléens).
    }
    En effet, ici, ton objet n'est instancié qu'une seule fois. La déclaration de celui ci est sauté aux autres appels que le premier de ta fonction.

    Bonne chance pour la suite
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  3. #3
    Nouveau membre du Club
    Inscrit en
    Août 2009
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 36
    Points : 36
    Points
    36
    Par défaut
    Mais comment as-tu le droit de faire ça ?

    Le o déclaré dans ma méthode est accessible ?

  4. #4
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    Citation Envoyé par la_urre Voir le message
    Mais comment as-tu le droit de faire ça ?

    Le o déclaré dans ma méthode est accessible ?
    pas directement, mais vu que ta méthode renvoie une référence dessus, on a donc, via cette référence accès à ton objet. C'est comme renvoyer une référence sur un membre privé. La variable est accessible au travers de la méthode

    bonne chance
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  5. #5
    Nouveau membre du Club
    Inscrit en
    Août 2009
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 36
    Points : 36
    Points
    36
    Par défaut
    Dans ce cas là, ce n'est pas :

    ?

  6. #6
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    Citation Envoyé par la_urre Voir le message
    Dans ce cas là, ce n'est pas :

    ?
    si effectivement, la parenthèse à sauté par oubli
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  7. #7
    Nouveau membre du Club
    Inscrit en
    Août 2009
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 36
    Points : 36
    Points
    36
    Par défaut
    C'est pour ça que je ne comprenais pas... Je croyais que tu arrivais à accéder à la variable déclarée dans la méthode (et qui s'appelle aussi o) par je ne sais quelle opération du Saint-Esprit... Comme ça, ça va mieux !

    Merci beaucoup pour ton aide !

  8. #8
    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,
    Citation Envoyé par la_urre Voir le message
    J'ai quelques questions à poser par rapport à ce problème. J'ai déjà fait le tour des FAQ, mais je n'ai rien trouvé pour m'aider. J'ai bien compris que ce problème s'applique également au champs membres de mes classes.
    Je suis un peu dubitatif par rapport à cette phrase. Peux-tu expliquer ton problème ? Car les membres (non statiques) d'une classe ont un ordre de construction bien déterminé (cf FAQ : Dans quel ordre sont construits les différents composants d'une classe ?).
    Et s'il s'agit de membres statiques de la classe, je serais curieux de connaître la conception qui t'amène à ce problème

  9. #9
    Nouveau membre du Club
    Inscrit en
    Août 2009
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 36
    Points : 36
    Points
    36
    Par défaut
    D'après ce que j'ai compris sur le fiasco, il s'applique également aux membres statiques des classes. J'ai peut-être mal saisi le problème, mais voici le type de choses que je rencontre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class A {
        static B *b;
    };
     
    class B{
        static A *a;
    };
    Est-ce que le fiasco s'applique dans ce cas ? Et serait-ce de même si ce ne sont pas des pointeurs mais des références, ou des objets (je pense qu'il y aurait un cycle dangereux pour les objets) ? Merci par avance.

  10. #10
    Nouveau membre du Club
    Inscrit en
    Août 2009
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 36
    Points : 36
    Points
    36
    Par défaut
    S'il vous plaît, j'ai vraiment besoin de savoir si le fiasco peut s'appliquer dans mon cas. Merci.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Pose toi la question de savoir comment tu va initialiser tes différents pointeurs, et tu auras ta réponse

    A doit initialiser un B qui doit initialiser un A... n'as tu pas l'impression de commencer à tourner en rond

    Comment pourrais tu briser ce cercle, sachant que tu peux décider, dans un premier temps, d'initialiser un pointeur à NULL
    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

  12. #12
    Nouveau membre du Club
    Inscrit en
    Août 2009
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 36
    Points : 36
    Points
    36
    Par défaut
    Bonjour et merci koala01,

    Peu importe l'architecture de ma classe, c'est juste un exemple que j'ai donné ici. Ce que je veux savoir est : Est-ce que le fiasco dans l'ordre d'initialisation des variables statiques s'applique aux champs membres d'une classe, où est-ce vraiment un problème qui concerne seulement les variables globales ?

    Merci.

  13. #13
    screetch
    Invité(e)
    Par défaut
    un champ statique est comme une variable globale. Lorsque tu initialise le champ statique de A, tu ne peux pas être sur que le champ statique de B est déjà initialisé, et vice et versa. Sauf si tu places les initialisations dans le meme fichier source, auquel cas tu as la garantie qu'ils seront initialisés dans l'ordre ou ils apparaissent dans le fichier source.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    //a.cpp
    B* A::b = new B;

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    //b.cpp
    A* B::a = new A;
    En admettant que le constructeur de A est besoin de l'instance b (mais pas le contraire), dans ce cas b doit être initialisé avant a.
    Si tu compiles a.cpp et b.cpp, probablement (bien qu'on en soit pas certain) cela va marcher; a.cpp etant compilé avant, l'initialisation sera faite avant, te donnant l'impression que ca marche. Puis si je recompile seulement b.cpp, alors l'initialisation dans b.cpp va être faite avant celle de a, et cette fois ci ca va planter.

    Si tu mets toutes tes variables statiques dans c.cpp alors (arrêtez moi si je me trompe) tu es certain que toute tes variables seront initialisées dans l'ordre (et même, dans le même ordre a chaque compilation, ce qui est bien pratique)

  14. #14
    screetch
    Invité(e)
    Par défaut
    un autre moyen de résoudre ce problème:
    http://en.wikibooks.org/wiki/More_C%.../Nifty_Counter

  15. #15
    Nouveau membre du Club
    Inscrit en
    Août 2009
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 36
    Points : 36
    Points
    36
    Par défaut
    Merci beaucoup pour cette réponse détaillée. Je crois que je vais aller au plus simple, même si ce n'est pas forcément le plus propre. Je vais initialiser tous mes membres statiques dans le .h, à la suite de la déclaration de la classe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // A.h
    class A{
        static B *b;
    };
     
    B *A::b = new B;
    Si j'ai bien compris je n'aurai pas de problèmes ainsi. Encore merci pour ta réponse claire et détaillée !

  16. #16
    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,
    Réponse en plusieurs temps :
    1/ L'ordre d'initialisation des membres statiques d'une classe suit les mêmes règles que celles des variables globales (donc les situations de fiasco sont identiques) ;
    2/ L'initialisation des variables non locales suit cependant un certain nombre de règles et n'est pas complètement aléatoire ;
    3/ L'ordre d'initialisation présenté ci-après concerne uniquement les variables dans une même unité de compilation et reste non spécifié (à ma connaissance) pour des unités de compilations distinctes. En d'autres termes, toutes les variables non locales définies dans a.cpp suivent ces règles mais on ne sait pas dire comment les initialisations de a.cpp s'articulent avec celles de b.cpp
    4/ On distingue deux types d'initialisations : les initialisations statiques (avec une expression constante ou les "zero-initialisation") et les initialisations dynamiques (les autres) ;
    5/ Les initialisations statiques des types POD (types primitifs + structures dont les membres non statiques sont POD, sans référence, sans operateur= ni destructeur définis par l'utilisateur en C++03) interviennent toujours avant les initialisations dynamiques ;
    6/ Les initialisations dynamiques interviennent dans l'ordre des définitions (contrairement aux membres non statiques d'une classe qui suit leur ordre de déclaration) dans l'unité de compilation.

    Il y a aussi quelques précisions selon que l'initialisation est faite avant ou après l'entrée dans le main mais il me semble que c'est plus pour les compilateurs que pour les utilisateurs.

    Ainsi :
    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
    struct A;
    struct B;
     
    A get_a_A();
    B get_a_B();
     
    struct A
    {
        static B b1;
        static B b2;
        static B *pb;
        static B *pb2;
    };
    struct B 
    {
        static A a1;
        static A a2;
        static A *pa;
    }; 
     
    B A::b1 = get_a_B(); // 1
    B* A::pb = 0; // 2
    A B::a1 = get_a_A(); // 3
    A B::a2 = get_a_A(); // 4
    B A::b2 = get_a_B(); // 5
    A* B::pa = 0; // 6
    B* A::pb2 = new B(); // 7
    L'initialisation est :
    1/ (2) et (6) dans n'importe quel ordre (2 puis 6 ou 6 puis 2) ;
    2/ (1)
    3/ (3)
    4/ (4)
    5/ (5)
    6/ (7)

    Deux remarques :
    1/ De tels cycles dans une conception sont un indicateur d'un problème ou d'un future problème : manque-t-il une classe pour marquer la relation entre A et B ?
    2/ En général, j'aime bien sortir ces éléments des classes A et B pour les mettre dans une classe dédiée qui se charge de la construction dans le bonne ordre.

    La résolution du fiasco ne passe pas par l'allocation dynamique comme dans :
    mais bien par l'utilisation d'une variable statique dans une fonction. La différence est que ton opérateur new peut très bien être utiliser des variables globales donc son utilisation ici peut être indéterminée. En revanche, une variable statique dans une fonction est construite au moment où on passe la première fois dedans. Donc, ce moment est (mieux) maîtrisé. Pour savoir s'il faut utiliser une allocation dynamique ou pas dans la fonction, cf la F.A.Q. ici et suivantes.

  17. #17
    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 la_urre Voir le message
    Merci beaucoup pour cette réponse détaillée. Je crois que je vais aller au plus simple, même si ce n'est pas forcément le plus propre. Je vais initialiser tous mes membres statiques dans le .h, à la suite de la déclaration de la classe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // A.h
    class A{
        static B *b;
    };
     
    B *A::b = new B;
    Si j'ai bien compris je n'aurai pas de problèmes ainsi.
    sisi :
    a.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct A
    {
        static int bug;
    };
    int A::bug=0;
    a.cpp :
    b.cpp :
    Compilation (à l'édition de lien ) : error LNK2005: "public: static int A::bug" (?bug@A@@2HA) déjà défini(e) dans a.obj (ceci est l'erreur visual, mais gcc et tout compilateur honnête te ressortira quelque chose de semblable)
    En définissant dans le .h, tu va la définir dans autant d'unité de compilation que le .h est inclus.
    La solution simple : l'utilisation d'une fonction.
    La solution à étudier : revoir la conception.

Discussions similaires

  1. Ordre en mémoire des variables dans une structure
    Par guillaume-13015 dans le forum C
    Réponses: 8
    Dernier message: 12/03/2013, 15h52
  2. Réponses: 9
    Dernier message: 21/03/2010, 21h42
  3. Initialiser des variables dans une méthode Statique
    Par ero-sennin dans le forum Langage
    Réponses: 10
    Dernier message: 07/12/2007, 15h26
  4. Initialisation des variables globales dans un package
    Par fred_hte_savoie dans le forum SQL
    Réponses: 2
    Dernier message: 17/04/2007, 10h26
  5. [DB2] Ordre de déclaration des variables
    Par Fatah93 dans le forum DB2
    Réponses: 1
    Dernier message: 04/05/2005, 17h18

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