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 :

Pointeur et changement d'adresse


Sujet :

C++

  1. #1
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut Pointeur et changement d'adresse
    Bonjour tout le monde!

    J'ai un problème que je n'arrive pas à m'expliquer.

    J'ai une classe A qui contient un pointeur sur une classe B. Cette classe B contient un pointeur sur la classe A...
    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
     
    class A
    {
     B* m_bPtr;
    public:
      A() {
        B(this);
      }
    };
     
    class B
    {
      A* m_aPtr;
    public:
      B(A* aPtr): m_aPtr(aPtr) {}
    };
    Mon problème est le suivant:

    Au cours de l'exécution de mon code, pendant une opération qui ne touche ni à la classe A ni à la classe B, le pointeur de la classe A situé dans la classe B change sans aucune raison.

    Sans parler d'un problème (évident?) de conception, je ne comprends ce genre de comportement.

    Avez-vous des idées?

    Merci d'avance.

  2. #2
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    Citation Envoyé par darkman19320 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class A
    {
     B* m_bPtr;
    public:
      A() {
        B(this);
      }
    };
    Déja là il y a un problème, je ne sais pas si c'est lié. Tu mets en pointeur vers A (this) dans un pointeur vers B, alors que A n'hérite pas de B.
    Sinon le reste du code ne permet pas de voir d'où vient le problème. Tu dois avoir quelque part un bout de code qui change ton pointeur et qui est appelé de manière intempestive.
    Si vraiment tu es perdu, mets un breakpoint dans ton compilo à tous les endroits qui pourraient changer le pointeur.

  3. #3
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Autant pour moi je me suis trompé quand j'ai recopié la classe A.

    Voici la bonne version:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class A
    {
    {
     B* m_bPtr;
    public:
      A() {
        m_bPtr = new B(this);
      }
    };

  4. #4
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Citation Envoyé par Rewpparo Voir le message
    Déja là il y a un problème, je ne sais pas si c'est lié. Tu mets en pointeur vers A (this) dans un pointeur vers B, alors que A n'hérite pas de B.
    Sinon le reste du code ne permet pas de voir d'où vient le problème. Tu dois avoir quelque part un bout de code qui change ton pointeur et qui est appelé de manière intempestive.
    Si vraiment tu es perdu, mets un breakpoint dans ton compilo à tous les endroits qui pourraient changer le pointeur.
    Attention, lis bien son code. Il appelle le constructeur de B qui prend un pointeur sur A comme paramètre. Donc pas de problème d'héritage.

    @darkman19320
    A priori, pas de problème normalement. Peux tu faire un code compilable qui reproduit le problème ?

  5. #5
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Voici un exemple en pièce jointe.

    Il contient les deux classes A et B, et un main.
    Il y a également un script CMake.
    Fichiers attachés Fichiers attachés

  6. #6
    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,

    Bon, il y a bien quelques aberrations, comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void A::setValue(int value)
    {
      m_bPtr->m_aPtr->value = value; //completement absurde mais en gros c'est ce qui est fait....
    }
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      for (int i= 0; i<1000000; ++i)
        {
          v.push_back(i+i);
          a.setValue(0);
        }
    mais, a priori, il n'y a strictement aucune raison pour que les adresses de tes pointeurs ne soient modifiées de manière aléatoire

    A l'instar de l'agent scully, je dirais que "la vérité est ailleurs"

    Ceci dit, les problèmes liés aux changement impromptus d'adresse des pointeurs sont souvent liés à des accès en écriture "hors écart" sur des tableaux gérés à la main (exemple, tenter de modifier tab[N] alors que le tableau est prévu pour ne contenir que N éléments (car les indexes valides vont de 0 à N-1 ), voir à un accès en écriture sur un tableau non alloué

    Si je peux te donner un conseil : commence déjà par remplacer toutes tes gestions de tableau dynamique C style (chaque fois que tu fais un Type * t = new Type[XXX] ) par des tableaux C++ : la classe vector, disponible dans l'espace de noms std par simple inclusion du fichier d'en-tete <vector> est faite pour cela

    Dans le meme ordre d'idée, abandonne les chaines de caractères C style ( char * str) au profit des chaines de caractères C++ : la classe string, elle aussi disponible dans l'espace de noms std (mais par inclusion du fichier d'en-tête <string> ) est elle aussi faite pour cela

    Si ces premières actions ne résolvent pas ton problème, vérifie que tous les accès aux différents tableaux se font dans les écarts admis (donc de l'index 0 à l'index N-1) et que tous tes pointeurs sont correctement initialisés.

    Si le problème n'est toujours pas résolu avec tout cela, il nous faudra du code un peu plus précis et complet pour te venir en aide
    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

  7. #7
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Merci pour ces réponses détaillées.
    Je vais me pencher pour remplacer l'ensemble des tableaux par des vecteurs.

    Je vous tiens au courant.

  8. #8
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    On a enfin trouvé... L'erreur venait d'un endroit complètement à côté de ce qu'indiquer gdb: on récupérait une adresse d'un objet temporaire et ce dernier était désaloué...

    Je ne comprends pas pourquoi il n'y a pas eu de warning à la compilation et encore moins pourquoi le debugger ne me montrer pas l'objet désaloué...

    Je met en Résolu mais si vous avez des idées pour les questions du dessus n'hésitez pas

    Encore merci.

  9. #9
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    GDB te montrera l'endroit où il rencontre une erreur, mais c'est parfois avant que ca se produit. Par exemple tu peux delete un pointeur, ensuite l'utiliser, gdb te montrera l'endroit où tu as déréférencé le pointeur, pas l'endroit où tu l'as delete.
    Quand à la compilation, essaie de monter le niveau de warning, avec -Wall g++ me sort ce genre de bugs.
    Si tu es sous Linux, valgrind permet de trouver ce genre de bug directement.

  10. #10
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Effectivement, je n'ai pas fait attention au niveau de warning. J'utilise CMake pour générer mes Makfile et j'étais persuadé qu'il mettait cette option par défaut ce qui n'est pas le cas.

    J'ai utilisé valgrind mais je n'ai pas réussi à interpréter correctement les données renvoyées.

    Merci pour tout.

  11. #11
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    J'utilise cmake moi aussi, et j'ai du rajouter à la main des options pour augmenter les warnings en ligne de commande. C'est une bonne ligne a avoir dans ton cmakelists dans tout projet d'une taille conséquente de toutes façons. Il faut modifier la variable CMAKE_CXX_FLAGS
    g++ par exemple ne dit pas par défaut si un chemin de contrôle ne renvoie pas de valeur dans une fonction qui a un type de retour. Et ca mène a de la corruption de stack difficile a débuguer.

    Pour valgrind, c'est un outil important si tu développe sous Linux. C'est très facile en C++ de se coder des bombes a retardement du genre de celle que tu avais. Si tu as encore des erreurs avec valgrind, il faut t'y intéresser car chaque erreur est une bombe a retardement potentielle. Les débusquer tôt te permettra de les corriger plus facilement, et en plus ça t'apprendra a ne plus les reproduire.
    En gros il te dit "invalid read of size X", ca veut dire que tu lis une zone mémoire qui est soit un pointeur null, soit un pointeur libéré, soit un pointeur non initialisé, soit autre chose du style. Vérifie la variable incriminée, voit d'où vient sa valeur, quelles variations elle subit.
    Typiquement dans le cas qui t'intéresse, il te dira "invalid read of size X" la première fois que tu déréférence ton pointeur après la sortie de la fonction où était la variable temporaire, car il a noté que la mémoire a été libérée à la sortie de la fonction. En le remontant un peu, tu trouves ton bug.

    Entre ça et le -Wall de g++, tu évite pas mal de problèmes.

  12. #12
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Merci pour les conseils.

    Je vais modifier la variable CMAKE_CXX_FLAGS pour que les warning soient plus explicites.

  13. #13
    Membre actif Avatar de Rewpparo
    Homme Profil pro
    Amateur
    Inscrit en
    Décembre 2005
    Messages
    170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Amateur

    Informations forums :
    Inscription : Décembre 2005
    Messages : 170
    Points : 281
    Points
    281
    Par défaut
    Pour info voila ce que j'ai dans mon cmakelists :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if(MSVC)
    	set(CMAKE_CXX_FLAGS "/W3 /MP")
    endif()
     
    if(CMAKE_COMPILER_IS_GNUCXX)
    	set(CMAKE_CXX_FLAGS "-Wall -g")
    endif()

  14. #14
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Je n'avais pas les options pour VS.

    C'est parfais encore merci!!

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

Discussions similaires

  1. Changement d'adresse IP
    Par mimiz dans le forum Réseau
    Réponses: 10
    Dernier message: 30/09/2006, 10h07
  2. changement d'adresse sous Tomcat
    Par gloglo dans le forum Tomcat et TomEE
    Réponses: 5
    Dernier message: 29/06/2006, 10h00
  3. Pointeurs et changement de types louches
    Par BenjaminLustrement dans le forum C
    Réponses: 8
    Dernier message: 08/06/2006, 13h34
  4. Réponses: 6
    Dernier message: 19/09/2005, 19h48
  5. changement d'adresse MAC
    Par Eusebius dans le forum Développement
    Réponses: 9
    Dernier message: 11/06/2004, 17h41

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