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 :

plantage apres avoir mis un destructeur


Sujet :

Langage C++

  1. #1
    Membre régulier Avatar de fifafou
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2016
    Messages
    173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Seine Maritime (Haute Normandie)

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

    Informations forums :
    Inscription : Janvier 2016
    Messages : 173
    Points : 92
    Points
    92
    Par défaut plantage apres avoir mis un destructeur
    Bonjour,
    Je fais un petit jeu de tank en C++ mais juste apres avoir rajouté un destructeur à ma classe balle,le programme compile mais plante à l’exécution
    Code main.cpp : 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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    #include <SDL/SDL.h>
    #include <SDL/SDL_image.h>
    #include <stdio.h>
    #include <SDL/SDL_rotozoom.h>
    #include <vector>
    #include <cmath>
    #include "balle.h"
    using namespace std;
    int bloc(int x,int y,int mat[][25])
    {
        return mat[x/20][y/20];
    }
    int main(int argc, char *argv[])
    {
        SDL_Surface *ecran = NULL,*block = NULL,*ice = NULL,*perso = NULL,*tank = NULL,*cannon = NULL;
        SDL_Rect pos_bloc,pos_perso;
        pos_perso.x=30;
        pos_perso.y=60;
        SDL_Event event;
        bool enf=0;
        int continuer = 1;
        int tempsPrecedent = 0, tempsActuel = 0;
        SDL_Init(SDL_INIT_VIDEO);
        ecran = SDL_SetVideoMode(1000,500, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
        SDL_WM_SetCaption("Jeu en SDL", NULL);
        cannon = IMG_Load("data/perso.png");
        tank = IMG_Load("data/perso.png");
        perso=tank;
        vector<Balle> balles;
        block = IMG_Load("data/bloc.png");
        ice = IMG_Load("data/glace.png");
        FILE* fichier = fopen("matrice.txt", "r");
        double px=30,py=60,vx=0,vy=0,an=0,angle;
        int mat[50][25],symb,i,j,sourisX,sourisY,time=SDL_GetTicks();
        for(j=0;j<25;j++)
        {
            for(i=0;i<50;i++)
            {
                symb=fgetc(fichier);
                if(symb=='\n')
                    symb=fgetc(fichier);
                mat[i][j]=symb;
            }
        }
        SDL_EnableKeyRepeat(10, 10);
        while (continuer)
        {
            SDL_PollEvent(&event);
            switch(event.type)
            {
                case SDL_QUIT:
                    continuer = 0;
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    enf=1;
                    break;
                case SDL_MOUSEBUTTONUP:
                    enf=0;
                    break;
                case SDL_MOUSEMOTION:
                    sourisX=event.button.x;
                    sourisY=event.button.y;
                    break;
            }
            SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 180,180, 250));
            for(int i=0;i<50;i++)
            {
                for(int j=0;j<25;j++)
                {
                    pos_bloc.x=20*i;
                    pos_bloc.y=20*j;
                    switch(mat[i][j])
                    {
                        case '1':
                            SDL_BlitSurface(block, NULL, ecran, &pos_bloc);
                            break;
                        case '2':
                            SDL_BlitSurface(ice, NULL, ecran, &pos_bloc);
                            break;
                        }
                }
     
            }
            Uint8 *state=SDL_GetKeyState(NULL);
            if(state[SDLK_LEFT])
                if(bloc(px-1,py,mat)!='0' || bloc(px-1,py+19,mat)!='0')
                    px=20*int((px+10)/20);
                else px-=3;
            if(state[SDLK_RIGHT])
                if(bloc(px+21,py,mat)!='0' || bloc(px+21,py+19,mat)!='0')
                    px=20*int((px+10)/20);
                else px+=3;
            if(state[SDLK_UP])
                if(bloc(px,py-1,mat)!='0' || bloc(px+19,py-1,mat)!='0')
                    py=20*int((py+10)/20);
                else py-=3;
            if(state[SDLK_DOWN])
                if(bloc(px,py+21,mat)!='0' || bloc(px+19,py+21,mat)!='0')
                    py=20*int((py+10)/20);
                else py+=3;
            px+=vx;
            py+=vy;
            perso = rotozoomSurface(tank, an, 1.0, 1);
            pos_perso.y=py+10-perso->h/2;
            pos_perso.x=px+10-perso->w/2;
            an=atan2(px+10-sourisX,py+10-sourisY)/3.14159265358979323846*180+90;
            if(enf && time+2<=SDL_GetTicks())
            {
                time=SDL_GetTicks();
                angle=atan2(px+10-sourisX,py+10-sourisY);
                balles.push_back(Balle(px+10,py+10,-6*sin(angle),-6*cos(angle)));
            }
            SDL_BlitSurface(perso, NULL, ecran, &pos_perso);
            for(i=0;i<balles.size();i++)
            {
                if(balles[i].update(ecran,mat)<0)
                    balles.erase(balles.begin());
            }
            SDL_Flip(ecran);
            tempsActuel = SDL_GetTicks();
            if (tempsActuel - tempsPrecedent > 20)
            {
                tempsPrecedent = tempsActuel;
            }
            else
            {
                SDL_Delay(20 - (tempsActuel - tempsPrecedent));
            }
        }
        SDL_FreeSurface(block);
        SDL_FreeSurface(perso);
        SDL_FreeSurface(ice);
        SDL_Quit();
        return EXIT_SUCCESS;
    }
    Code balle.h : 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
    #include <SDL/SDL.h>
    #include <SDL/SDL_image.h>
    #ifndef DEF_BALLE
    #define DEF_BALLE
    class Balle
    {
        public:
        Balle();
        Balle(double x,double y,double vx,double vy);
        ~Balle();
        int update(SDL_Surface* ecran,int mat[][25]);
        private:
        double vy,y;
        double vx,x;
        int d;
        SDL_Surface* balle;
        SDL_Rect pos_balle;
    };
    #endif
    Code balle.cpp : 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
    #include <SDL/SDL.h>
    #include <SDL/SDL_image.h>
    #include "balle.h"
    using namespace std;
    int bloc(int x,int y,int mat[][25]);
    Balle::Balle():
        vx(1),
        vy(1),
        balle( IMG_Load("data/balle.png")),
        d(100)
    {
        x=50;
        y=50;
        pos_balle.x = 50;
        pos_balle.y = 50;
    }
    Balle::Balle(double m_x,double m_y,double m_vx,double m_vy):
        vx(m_vx),
        vy(m_vy),
        balle( IMG_Load("data/balle.png")),
        d(100)
    {
        x=m_x;
        y=m_y;
        pos_balle.x =x;
        pos_balle.y =y;
    }
    Balle::~Balle()
    {
        SDL_FreeSurface(balle);
    }
    int Balle::update(SDL_Surface* ecran,int mat[][25])
    {
        x+=vx;
        y+=vy;
        if((bloc(x,y-5,mat)=='1' && vy<0) || (bloc(x,y+5,mat)=='1' && vy>0))
            vy=-vy;
        if((bloc(x-5,y,mat)=='1' && vx<0) || (bloc(x+5,y,mat)=='1' && vx>0))
            vx=-vx;
        pos_balle.x=x-5;
        pos_balle.y=y-5;
        SDL_BlitSurface(balle, NULL,ecran,&pos_balle);
        d-=1;
        return d;
    }
    quelqu'un saurai trouver pourquoi?

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

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

    Informations forums :
    Inscription : Février 2005
    Messages : 5 074
    Points : 12 120
    Points
    12 120
    Par défaut
    Pour faire court : Rules of Five
    https://en.wikipedia.org/wiki/Rule_o...B_programming)

    En clair, lors d'une affectation (ce que fait un std::vector à la chaine), vous partagez le pointeur "balle", donc des "double free" en cascade.

  3. #3
    Membre régulier Avatar de fifafou
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2016
    Messages
    173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Seine Maritime (Haute Normandie)

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

    Informations forums :
    Inscription : Janvier 2016
    Messages : 173
    Points : 92
    Points
    92
    Par défaut
    j'ai regardé le lien mais je n'ai pas compris comment résoudre ça.
    Comment peut on faire?

  4. #4
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    As-tu au moins compris ce qu'il se passe dans ton code?
    Certains membres dans un objet, ne peuvent pas être copiés sans risque.
    Dans ton cas la surface 'balle' contient une allocation dynamique, quand on copie une Balle, on écrase ce pointeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Balle b1;    // réserve dans b1.balle une surface
    Balle b2;    // réserve dans b2.balle une surface
    b1 = b2;     // b1.balle a reçu la valeur de b2.balle, les 2 pointent sur la même surface!
    b2.~Balle(); // à la destruction de b2, ton destructeur détruit la surface allouée par b2
    b1.~Balle(); // à la destruction de b1, le destructeur tente de re-désallouer la surface allouée par b2!
    // finalement la surface allouée par b1 ne sera jamais libérée, et celle pour b2 sera désallouée 2 fois!
    Ce que l'on peut faire :
    a) Ici b1 et b2 pourrait partager la même surface (car c'est une image qui ne sera que lue)
    b) ou bien, ajouter le code nécessaire pour gérer 'proprement' les copies, c'est indiqué dans 'Rule of Five'.

    Méthode (a), on va considérer que la surface est une donnée de classe plutôt que d'objet. Elle sera réservée lors de la création de la première Balle, et on peut opter pour ne jamais la libérer.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Balle {
        ...
        static SDL_Surface* balle; // donnée de classe (toutes les Balle partagent cette unique balle)
        ...
    };
    
    /*static*/ Balle::SDL_Surface* balle = nullptr;
    
    Balle::Balle() : vx(1), vy(1), d(100) {
       if ( !balle ) balle = IMG_Load("data/balle.png"); // Attention ce code est à améliorer s'il y a multithreading
       ...
    }
    Méthode (b), appliquer consciencieusement la règle des cinq ou la règle des trois. Il est impératif et inévitable de bien les comprendre, c'est une des bases du langage C++. Si le lien ne t'a pas suffit, il existe de nombreuses références à ce sujet y compris en français.
    Ici tu dois définir (sans faire d'erreur) au moins : un constructeur par copie, un opérateur de copie et un destructeur pour gérer correctement cette donnée, sans cela le compilateur considérerais une simple copie membre à membre. Je t'encourage à essayer et à poster ton essai, nous t'aiderons.

Discussions similaires

  1. [Débutant] Faire un boulot après avoir été mis en icône
    Par Guyt54 dans le forum C++Builder
    Réponses: 2
    Dernier message: 01/04/2012, 01h31
  2. [MySQL] Syntaxe erreur apres avoir mis un quote '
    Par AyManoVic dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 12/07/2010, 16h50
  3. Réponses: 2
    Dernier message: 13/11/2005, 20h48
  4. TStringlist.SaveToFile apres avoir oté l'attribut Read-only
    Par Alex Laforest dans le forum Langage
    Réponses: 1
    Dernier message: 23/10/2005, 00h05
  5. [NAV 2004] Bug après avoir renommé la corbeille
    Par Halleck dans le forum Windows
    Réponses: 2
    Dernier message: 29/02/2004, 21h06

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