Partage
  • Partager sur Facebook
  • Partager sur Twitter

segfault lors d'appel de fonction virtuelle

Sujet résolu
    21 juin 2017 à 15:05:47

    Salut a tous !

    Je suis en phase de test d'une classe qui a pour fonction de gerer la main loop d'une application lorsque j'appelle la fonction run().
    Cette fonction run appelle des fonctions virtuelles de la classe Application, mais je tombe sur un segfault que je n'arrive pas a m'expliquer.
    Voila le code :

    Engine.hpp :

    #ifndef ENGINE__HPP_
    #define ENGINE__HPP_
    
    #include "Application.hpp"
    
    class Engine 
    {
    public:
    	void run (Application * app);
    	
    };
    
    #endif

    Engine.cpp :

    #include "Engine.hpp"
    
    #include <chrono>
    
    
    double now ()	// return the current date in seconds
    {
    	using namespace std::chrono;
    	
    	return duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
    }
    
    void Engine::run (Application * app)
    {
    	double t = 0.0;
    	
    
    	app->setup();
    	
    	double currenttime = now();
    	double accumulator = 0.0;
    	
    	while (app->running())
    	{
    		
    		double newtime = now();
    		double frametime = newtime - currenttime;
    		
    		if (frametime > 0.25) frametime = 0.25;
    		currenttime = newtime;
    		
    		accumulator += frametime;
    		while (accumulator >= app->dt())
    		{
    			float dt = app->dt(); 
    			app->input();           // L'APPEL PROVOQUE UN SEGFAULT
    			app->update(t, dt);
    			
    			t += dt;
    			accumulator -= dt;
    		}
    		const double alpha = accumulator / app->dt();
    		
    		app->render (alpha);
    	}
    	app->cleanup();	
    }
    


    Application.hpp:

    #ifndef APPLICATION__HPP_
    #define APPLICATION__HPP_
    
    class Application 
    {
    public:	
    	virtual ~Application() { };
    
    	virtual void setup () { };
    	virtual void cleanup () { };
    	
    	virtual void input () { };
    	virtual void update (double t, double dt) { };
    	virtual void render (double alpha) { };
    	
    	
    	bool running () { return _running; };
    	float dt () { return _dt; };
    
    protected:
    	void start() { _running = true; };
    	void stop()  { _running = false; };
    	
    	float getDt() { return _dt; };
    	void setDt(float _dt) { this->_dt = _dt; };
    	
    private:
    	bool _running;
    	float _dt;
    };
    
    
    #endif

    Test.cpp :

    #include "EZApp.hpp"
    
    #include <SDL2/SDL.h>
    
    class Test : public Application
    {
    public:
    	void setup () override;
    	void input () override;
    	void update (double t, double dt) override;
    	void render (double alpha) override;
    	void cleanup () override;
    
    private:
    	SDL_Window * window;
    	SDL_Renderer * renderer;
    
    	float x, y;		// in Unit
    	float dx, dy;	// in Unit per Second
    };
    
    void Test::setup ()
    {
    	SDL_Init (SDL_INIT_VIDEO);
    	window = SDL_CreateWindow (
    		"Test", 
    		SDL_WINDOWPOS_UNDEFINED,
    		SDL_WINDOWPOS_UNDEFINED,
    		640,
    		480,
    		0
    	);
    	
    	renderer = SDL_CreateRenderer (
    		window,
    		-1,
    		0
    	);
    	
    	x = 320; y = 240;
    	dx = 100; dy = 100;
    	
    	
    	setDt( 1.0 / 60.0 );
    	start();
    }
    
    void Test::input ()
    {
    	SDL_Event e;
    	while (SDL_PollEvent (&e)) {
    		switch (e.type) {
    			case SDL_QUIT : stop(); break;
    			default : break;
    		}	
    	}
    }
    
    void Test::update (double t, double dt)
    {
    	x += (dx * dt);
    	y += (dy * dt);
    	
    	if (x > 640 || x < 0) dx *= -1;
    	if (y > 480 || y < 0) dy *= -1;
    }
    
    void Test::render (double alpha)
    {
    	SDL_SetRenderDrawColor (renderer, 0, 0, 0, 255);
    	SDL_RenderClear (renderer);
    	
    	SDL_SetRenderDrawColor (renderer, 255, 255, 255, 255);
    	
    	SDL_Rect rect;
    	rect.x = x - 2;
    	rect.y = y - 2;
    	rect.w = 4;
    	rect.h = 4;
    	SDL_RenderFillRect (renderer, & rect);
    	
    	SDL_RenderPresent (renderer);
    }
    
    void Test::cleanup ()
    {
    	SDL_DestroyRenderer (renderer);
    	SDL_DestroyWindow (window);
    	SDL_Quit ();
    }
    
    
    int main (void)
    {
    	Application * app = new Test();
    	Engine engine;
    	
    	engine.run (app);
    	return 0;
    }
    

    Si quelqu'un pourrait bien me donner une explication sur le probleme, parce que je n'arrive vraiment pas a voir ce qui ne va pas.


    -
    Edité par redlantern 21 juin 2017 à 15:07:56

    • Partager sur Facebook
    • Partager sur Twitter
      21 juin 2017 à 15:31:24

      Il dit quoi le débogueur ?

      -
      Edité par bacelar 21 juin 2017 à 16:04:59

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        21 juin 2017 à 15:45:27

        J'ai fait un test avec GDB et il me dit absolument rien, le programme fonctionne sous GDB mais pas sans donc oui c'est une erreur bizarre
        • Partager sur Facebook
        • Partager sur Twitter
          21 juin 2017 à 20:16:22

          Salut,

          Déjà, chaque tentative de déréférencement d'un pointeur doit ad minima être précédée d'une assertion (assert(ptr && "null pointer detected");, par exemple)

          Ensuite, si tu essayais de transmettre ton application sous forme de référence au lieu de la transmettre sous forme de pointeur, tu pourrais sans doute t'éviter bien des soucis.

          C'est d'autant plus vrai que tu connais, de toute évidence, le type de ton application dans ta fonction main(test, dans le cas présent).  Tu n'as donc aucune raison de recourir à l'allocation dynamique pour app; un code proche de

          int main(){
              test app{/* paramètres éventuels */};
              engine.run(app);
          }

          faisant tout aussi bien l'affaire (une fois que ton application sera transmise par référence, s'entend)

          Quant à ton problème particulier, il faudra aller voir plus en profondeur, mais je ne serais pas étonné qu'il y ait un delete app qui traine quelque part ;)

          Enfin, tu devrais avoir recours à ==>la déclaration anticipée<== pour que ta classe engine connaisse la classe application ;)

          • Partager sur Facebook
          • Partager sur Twitter
          Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
            22 juin 2017 à 1:45:47

            Salut et merci @koala1 , effectivement passer ma structure par reference plutôt que par pointeur a eliminé le probleme !
            (au passage je ne savais pas qu'on pouvait passer une reference sur une classe abstraite, donc merci de m'apprendre ca)
            Il n'y a pas vraiment besoin de déclaration anticipé puisqu'il n'y a pas de reference a Engine dans Application, du coup il n'y a pas de probleme de dépendance "croisé" entre les deux classes

            • Partager sur Facebook
            • Partager sur Twitter
              22 juin 2017 à 10:14:04

              Le fait de passer la structure par référence permet d'avoir un code plus robuste et plus cohérent; et de corriger le défaut de ton code qui "oubliait" de libérer l'Application.
              En l'occurrence cela n'a rien à voir avec le segfault. N'as-tu pas modifié autre chose par la même occasion?

              • Partager sur Facebook
              • Partager sur Twitter

              En recherche d'emploi.

                22 juin 2017 à 18:19:35

                @Dalfab, non je n'ai rien modifié d'autre, a part les appels de fonction (passer de app->update() a app.update()) mais moi aussi je m'interroge sur le segfault :
                effectivement j'ai oublié de liberer l'espace mémoire a la fin du programme, mais a ce moment là il aurait du fonctionner puis me signaler le segfault lors de la sortie de main, non ?

                Ce qui me parait le plus bizarre c'est que l'application marchait sous GDB, mais pas sans GDB, et que GDB ne me signale aucun problème

                • Partager sur Facebook
                • Partager sur Twitter

                segfault lors d'appel de fonction virtuelle

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                • Editeur
                • Markdown