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

SL & STL C++ Discussion :

[std::list] changement incompréhensible des adresses mémoires


Sujet :

SL & STL 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 2004
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 15
    Par défaut [std::list] changement incompréhensible des adresses mémoires
    Bonjour à tous,

    débutant en C++ (mais déjà confirmé en Java, donc pas débutant en programmation), je suis confronté à un problème de mémoire que je ne comprend pas (n'ayant jamais eu à gêrer la mémoire auparavent). Le programme est un petit jeu en 2D.

    J'utilise Visual C++ .net, et mon problème se situe dans une liste (std::list). J'utilise une liste de pointeurs vers des objets (list<GameObject*>) dont j'actualise l'état et que j'affiche grâce à la méthode GameObject::refresh().

    voici le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void GameState::render()
    {
        list<GameObject*>::iterator iter;
     
        for( iter = m_renderable_objects.begin(); iter != m_renderable_objects.end(); iter++) 
        {
            if(!((*iter)->getParent()))
                (*iter)->refresh(SDL_GetTicks());
        }
    }
    Parmis ces GameObject à actualiser et afficher, deux sous-classe sont incriminée : Sea et Boat.
    Boat possède une liste de GameObject enfants. On a donc (en simplifiant le vrai code) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void Boat::refresh(int _time)
    {
        list <GameObject *>::iterator end = m_children.end();
        for (list <GameObject *>::iterator iter = m_children.begin(); iter != end; ++iter)
        {
            (*iter)->refresh(_time);
    }
    Sea, quand à elle, dessine dans son Sea::refresh() une spline, et donc possède un double *m_second_derivative qui sert à stocker un tableau de double représentant la dérivée seconde des points de contrôles de la spline (il s'agit d'une spline cubique).
    Voilà donc le code (simplifié là encore) :
    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
     
    void Sea::refresh(int _time)
    {
        animate();
        calculateSecondDerivative();
        display();
    }
     
    void Sea::calculateSecondDerivative()
    {
        double yp0 = (m_ctrl_points[1].getY()-m_ctrl_points[0].getY()) /
                     (m_ctrl_points[1].getX()-m_ctrl_points[0].getX());
        double ypnm1 = (m_ctrl_points[m_nb_ctrl_points-1].getY()-m_ctrl_points[m_nb_ctrl_points-2].getY()) /
                       (m_ctrl_points[m_nb_ctrl_points-1].getX()-m_ctrl_points[m_nb_ctrl_points-2].getX());
        int i,k;
        double p,qn,sig,un,*u;
     
        u = new double[m_nb_ctrl_points];
     
        //evite la pente initiale trop importante
        if (yp0 > 1e30)
            m_second_derivative[0]=u[0]=0.0;
        else
        {
            m_second_derivative[0] = -0.5;
            u[0]=(3.0/(double)(m_ctrl_points[1].getX()-m_ctrl_points[0].getX()))*((double)(m_ctrl_points[1].getY()-m_ctrl_points[0].getY()) /
                 (double)(m_ctrl_points[1].getX()-m_ctrl_points[0].getX())-yp0);
        }
     
        for (i=1;i<m_nb_ctrl_points-1;i++)
        {
            sig=(double)(m_ctrl_points[i].getX()-m_ctrl_points[i-1].getX())/(double)(m_ctrl_points[i+1].getX()-m_ctrl_points[i-1].getX());
            p=sig*m_second_derivative[i-1]+2.0;
            m_second_derivative[i]=(sig-1.0)/p;
            u[i]=(double)(m_ctrl_points[i+1].getY()-m_ctrl_points[i].getY())/(float)(m_ctrl_points[i+1].getX()-m_ctrl_points[i].getX()) -
                 (double)(m_ctrl_points[i].getY()-m_ctrl_points[i-1].getY())/(double)(m_ctrl_points[i].getX()-m_ctrl_points[i-1].getX());
            u[i]=(6.0*u[i]/(double)(m_ctrl_points[i+1].getX()-m_ctrl_points[i-1].getX())-sig*u[i-1])/p;
        }
     
        //evite la pente finale trop importante
        if (ypnm1 > 0.99e30)
            qn=un=0.0;
        else {
            qn=0.5;
            un=(3.0/(double)(m_ctrl_points[m_nb_ctrl_points-1].getX()-m_ctrl_points[m_nb_ctrl_points-2].getX()))*(ypnm1-(double)(m_ctrl_points[m_nb_ctrl_points-1].getY() -
               m_ctrl_points[m_nb_ctrl_points-2].getY())/(double)(m_ctrl_points[m_nb_ctrl_points-1].getX()-m_ctrl_points[m_nb_ctrl_points-2].getX()));
        }
     
        m_second_derivative[m_nb_ctrl_points-1]=(un-qn*u[m_nb_ctrl_points-2])/(qn*m_second_derivative[m_nb_ctrl_points-2]+1.0);
        for (k=m_nb_ctrl_points-2;k>=0;k--)        m_second_derivative[k]=m_second_derivative[k]*m_second_derivative[k+1]+u[k];
     
        delete [] u;
    }

    Et si vous êtes encore là (je sais que cet exposé est un peu long, mais j'ai peur de ne pas être clair !), voilà où est le problème :

    lors de la première itération de ma boucle principale de jeu, les adresses mémoires de la liste Boat::m_children sont les suivantes (d'après le debugger) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    m_children::Myhead 0x003e2b60
    m_children::_Next 0x003e5bd8
    m_children::_Prev 0x003e5bd8
    la liste ne contient qu'un élément et j'observe bien m_children::_Mysize = 1

    eh bien juste après le passage dans Sea::calculateSecondDerivative(), qui est affiché juste après, ces valeurs changent pour des valeurs bizarres :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    m_children::Myhead 0x003e2b60
    m_children::_Next 0x503e382b
    m_children::_Prev 0xbeccc318

    evidemment, dès la deuxième itération, le programme plante avec un joli "Access violation reading location 0x503e382b", ce qui me parait logique.

    Ce qui m'est incompréhensible, c'est comment le remplissage d'un tableau de double dans une classe peut agir sur les adresses d'une liste qui est dans une autre classe...

    Peut-être est-ce le symptôme d'un problème qui vient d'ailleur, mais je ne sais pas du tout où regarder...

    Quelqu'un aurait-il une piste ?

    Antoine

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Tes fonctions membres sont bien virtuelles ?

  3. #3
    tut
    tut est déconnecté
    Membre éclairé
    Avatar de tut
    Inscrit en
    Juillet 2002
    Messages
    373
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 373
    Par défaut
    ça sent le "jardinage"...
    Vérifie que tu n'écries pas au-delà des limites de tes tableaux, parce que si c'est le cas, tu peux très bien aller écrire dans ta liste.... et alors là...

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

    Informations forums :
    Inscription : Février 2004
    Messages : 15
    Par défaut
    Malheureusement, il me semble bien que je ne sors pas des bornes du tableau.
    Voilà un extrait du constructeur de Sea :
    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
     
    Sea::Sea(const float _width, const float _height, const int _sampling)
    {
        m_nb_ctrl_points = (int)ceilf(m_width/145);
        m_ctrl_points = new Position[m_nb_ctrl_points];
        m_ctrl_points_ref = new Position[m_nb_ctrl_points];
     
        float step = m_width / (m_nb_ctrl_points-1);
     
        m_second_derivative = new double[m_nb_ctrl_points];
     
        for (int i = 0; i < m_nb_ctrl_points; ++ i)
        {
            m_ctrl_points[i] = Position(i * step, 0);
            m_ctrl_points_ref[i] = m_ctrl_points[i];
            m_second_derivative[i]=0;
        }
     
    }
    et voilà à quoi ressemble la boucle dans laquelle les adresses changent de manière suspecte, dans Sea::calculateSecondDerivative()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        for (i=1;i<m_nb_ctrl_points-1;i++)
        {
            ...
        }
    donc là, je boucle à partir du deuxième élément jusqu'à l'avant dernier. Aucune raison de sortir des bornes donc... J'ai tout de même vérifié si m_nb_ctrl_points ne change pas de valeur, et sa valeur reste toujours la même.

    Donc je reste bloqué sur cette erreur. Des idées ?

    Antoine

    EDIT: GameObject::refresh() est déclarée virtuelle, ainsi que Boat::refresh() et Sea::refresh().

  5. #5
    mat.M
    Invité(e)
    Par défaut
    for (int i = 0; i < m_nb_ctrl_points; ++ i)



    En C pour remplir un tableau de 10 éléments on procéde comme cela :
    i est d'abord initialisé à 0 puis si i=10 alors on sort de la boucle
    int entiers[10];
    int i;
    for(i=0;i<10;i++) entiers[i]=0;

    pour la boucle que tu as donnée précedemment , i est incrémenté AVANT d'être affecté donc les bornes de m_ctrl_points[i] vont être dépassées

  6. #6
    Membre chevronné
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Par défaut
    Non Mat.M. for(int i=0; i < 10; ++i) et for(int i=0; i < 10; i++) donne 10 itérations avec i variant de 0 à 9.
    Si tu veux t'en convaincre, écris un programme de test

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 03/07/2014, 22h39
  2. Réponses: 15
    Dernier message: 30/09/2008, 23h36
  3. Réponses: 2
    Dernier message: 29/05/2008, 18h28
  4. std::list, std::vector et allocation mémoire
    Par buzzkaido dans le forum SL & STL
    Réponses: 20
    Dernier message: 15/06/2007, 15h58

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