780

Oh non, j'en veux pas de ce troll, ou alors forker, mais j'aurais certainement d'autres questions très C++ d'ici peu grin

781

Pas besoin de lancer de troll ^^
[Cross]
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

782

Bon, après s'être élevé dans les nuages conceptuels, retour aux merdes habituelles cheeky
J'ai un constructeur :
Task::Task() : m_currentTask(0), m_SDLState(false), m_SDLInit(false), m_screen(1024, 768, 32)
Le problème, c'est que m_screen est un objet qui peut provoquer une exception à l'initialisation. Je le mets où mon catch, vu qu'il n'y a pas de try ? cheeky

783

Autour de l'instanciation de ton objet Task.
avatar
Maintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

784

./782 > T'en mets pas.

Si le constructeur de m_screen foire, alors le constructeur de ton objet Task foire, c'est normal:
Si on te force à appeler les constructeurs de membres dans le constructeur de ton objet, c'est parce que les objets non initialisés ne sont pas valides/sont interdits.
Plus exactement, le seul endroit où tu peux accéder à un objet non initialisé, c'est au sein du constructeur de celui-ci (plutôt logique non ?)
Bref, un objet doit être initialisé entièrement, point.
Si une partie de ton objet échoue à être initialisée, alors ton objet entier échoue à être initialisé, et tu remontes la chaîne comme ça. (tout aussi logique, non ?)

Après il faut réfléchir à ce que signifie ton exception… Si c'est une erreur fatale, ça prend tout son sens qu'elle interrompe la création de l'objet.
Si en revanche, c'est une erreur normale (par exemple la classe Joystick échoue parce qu'il n'y a pas de joystick sur le PC), tu dois probablement revoir ton design et modifier ce champ en un pointeur vers objet. (Le pointeur peut être NULL, lui)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

785

Link (./765) :
PS: Il me semble que la référence const en général est une exception aux règles de scoping, pas seulement dans le contexte des traitements d'exception: Notamment, je crois me rappeler qu'une référence const vers un temporaire non-nommé étend sa durée de vie à celle de la référence.

C'est possible (je n'ai pas vérifié), mais ça n'a rien à voir avec le cas du throw. Et ça ne résout quand-même pas tous les problèmes, par exemple une référence const peut être copiée, et du coup cette exception ne sert plus (parce que la référence d'origine a disparu) et il n'y a aucun type de warning pour ça. Par exemple, le plantage corrigé dans http://websvn.kde.org/?revision=977693&view=revision était dû à une référence const sur un temporaire non nommé.

C'est justement une des raisons pour lesquelles le C++0x connaît les références rvalue, ça permet de détecter et donc d'empêcher (à coups d'erreurs au moment de la compilation) ces fuites de références qui font boguer les programmes.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

786

Ok, merci. De toute façon j'ai modifié ma liste d'initialisation :
Task::Task() : m_currentTask(0), m_SDLState(false), m_SDLInit(false), m_screen()
Et Screen::Screen() qui construit m_screen ne fait rien.

Par contre, j'ai une erreur sûrement conne, mais je ne comprends pas ce qui va pas, ça me semble incohérent confus
Je fais, dans Task(), un appel à Screen pour initialiser réellement m_screen, dans un catch bien comme il faut :
    try
    {
        m_screen(1024, 768, 32);
    }

Et là, il me met :
error: no match for call to '(Screen) (int, int, int)'

Ah bon ?!?
Voici ma classe screen :
class Screen
{
    public:

        Screen();
        ~Screen();
        Screen(int width, int height, int bpp);        // <==== Et ça c'est pour les chiens ?!?
        SDL_Surface *getScreenPtr(void);
        void update(void);
        void setClip(SDL_Rect *Rect);


    private:

        Screen(const Screen&);
        Screen operator= (const Screen&);
        SDL_Surface *m_screen;
        int m_width;
        int m_height;
        int m_bpp;
        int m_flags;
};

D'où voit-il que Screen(int, int, int) n'existe pas ?!?

787

Il manque un include peut être?
Sinon (ràv), soit tu mets toujours le nom des variables dans les prototypes des méthodes, soit tu ne les mets jamais #maniac#

edit: oula non, je comprends même pas ce que tu fais en fait :s
edit2: Ahh, j'ai compris. Alors Folco, un constructeur ne s'appelle qu'une fois grin Là tu va devoir faire m_screen.init(1024, 768, 32);

788

Non, l'include y est (sinon, m_screen() n'aurait pas marché non plus).

Sinon, oui, t'as raison, je vais lisser ça grin

789

Encore un truc con:
Une objet est initialisé. Une fois. Et une seule.
La seule solution c'est le pointeur comme je l'ai expliqué tongue

(En fait là ce que t'as essayé de faire, c'est apeller l'opérateur () sur ton objet, au cas où tu te demanderais ^^)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

790

Rah merde, le traitre embarrassed
Oué, j'ai trouvé une autre méthode, j'implémente et c'est prêt dans 10 minutes...

791

Voilà. Screen(int, int, int) met une variable privée à true si ça a marché. Task appelle m_screen.getState() pour savoir si son initialisation s'est bien passée. Torché, c'est beaucoup plus simple. embarrassed

792

Je trouve pas ça très très propre… Y'a moyen de faire mieux niveau design tongue
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

793

Je me doute bien cheeky
Mais ça fait clair et concis (je sais, osef grin)
Task::Task() : m_currentTask(0), m_SDLState(false), m_screen(1024, 768, 32)
{
    if (m_screen.getScreenState())
        m_SDLState = true;
}

794

T'aurais au moins changé ton modèle objet comme suggéré dans l'édit2 de Jyaif, ça aurait été tout aussi concis, et plus propre dans ce cas précis. (je ne connais pas les détails du reste de ton code donc je peux pas non plus le certifier :] )
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

795

Ah ben voilà, j'avais pas vu ses edit \o/

Meric bien grin En effet, je crois que c'est la bonne solution ^^

796

Bon, sur vos conseils avisés, j'ai donc écrit ça :
Task::Task() : m_currentTask(0), m_SDLState(false), m_screen()
{
    try
    {
        m_screen.init(1024, 768, 32);
    }
    catch (ScreenException(exception))
    {
        fprintf(stderr, "%s\n", exception.getErrorString().c_str());
        return;
    }
    m_SDLState = true;
}

Ici aussi, ne vaudrait-il pas mieux lancer une exception TaskException plutôt que de jouer avec un booléen, sur le même principe que pour Screen ?

797

pourquoi ne pas plutôt mettre le try autour de la construction de Task et laisser l'init de m_screen dans son constructeur ?
si m_screen() échoue, Task aussi et la fonction qui l'a crée traite l'erreur

comme ça tu n'auras pas à vérifier l'état de m_SDLState après pour savoir si tout s'est bien passé
edit: j'ai retrouvé le post ou il semble qu'il y ait le main correspondant. tu devrais plutot faire un truc comme ça :
int main (void) 
{ 
	try
	{
		Task MainTask;
		return MainTask.ManageTask(TASK_INTRO);
	}
	catch(const ScreenException &exception)
	{
		fprintf(stderr, "%s\n", exception.getErrorString().c_str()); 
		return EXIT_FAILURE;
	}
}

Task::Task() : m_currentTask(0), m_SDLState(false), m_screen(1024, 768, 32) 
{ 
	/* ... */
}
avatar

798

Merci aze, c'était bien le sens de ma quetion :
Folco (./796) :
Ici aussi, ne vaudrait-il pas mieux lancer une exception TaskException plutôt que de jouer avec un booléen, sur le même principe que pour Screen ?

Donc je vais faire comme t'as dit, c'est plus rigoureux. C'est juste que je trouvais visuellement le main plus propre sans le try/catch #argument# trioui

799

Voilà, j'ai rectifié comme tu m'as dit, c'est en effet beaucoup plus propre, ça évite un membre et une méthode pour vérifier l'initialisation (surtout que la classe exception existe déjà) :#include <SDL.h> #include "task.hpp" #include "screen_except.hpp" int main (void) { int ret = EXIT_FAILURE; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) != 0) { fprintf(stderr, "Couldn't load SDL\n"); return ret; } try { Task MainTask; ret = MainTask.ManageTask(TASK_INTRO); } catch (ScreenException const & exception) { fprintf(stderr, exception.getErrorString().c_str()); } SDL_Quit(); return ret; }
Task appelle son constructeur devenu tout simple :Task::Task() : m_CurrentTask(0), m_MainScreen(1024, 768, 32) { }
qui appelle Screen :Screen:: Screen(int width, int height, int bpp) : m_Screen(NULL), m_Width(width), m_Height(height), m_Bpp(bpp), m_Flags(SDL_HWSURFACE | SDL_ANYFORMAT | SDL_DOUBLEBUF) { m_Screen = SDL_SetVideoMode(m_Width, m_Height, m_Bpp, m_Flags); if (m_Screen == NULL) { m_Flags = SDL_SWSURFACE | SDL_ANYFORMAT; m_Screen = SDL_SetVideoMode(m_Width, m_Height, m_Bpp, m_Flags); if (m_Screen == NULL) throw (ScreenException(SDL_GetError())); } }

Ca me parait effectivement beaucoup plus académique. Merci encore. happy

(Et surtout si ça va pas et avez encore du courage pour m'aider, ne vous gênez pas, j'ai presque tout à apprendre grin)

800

Comment initialiser une structure membre d'une classe dans une liste d'initialisation ? Sans extension GNU de préférence...

m_offset({offsetX, offsetY, width, height})ne passe pas...

La structure :
typedef struct{
  Sint16 x, y;
  Uint16 w, h;
} SDL_Rect;

801

struct SDL_Rect {
  Sint16 x, y;
  Uint16 w, h;
  // Constructeur
  SDL_Rect(Sint16 x, Sint16 y, Uint16 w, Uint16 h)
  {
    this->x = x;
    this->y = y;
    this->w = w;
    this->h = h;
  }
};

Et ensuite :
m_offset(offsetX, offsetY, width, height)
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

802

Euh, tu me propose de faire un constructeur pour la structure SDL_Rect ? Mais je dois le mettre où ? Je comprends bien l'idée, mais SDL_Rect est défini, comment lui adjoindre ce constructeur dans mon code ?

803

Je pense qu'il ne savait pas que SDL_Rect est une structure définie par une librairie.
Tu peux essayer:

SDL_Rect m_offset = {offsetX, offsetY, width, height};

804

Si c'est une variable membre tu ne peux tout simplement pas si elle n'a pas de constructeur (une des nombreuses joies du C++ qui font que je l'adore). Pareil le jour où tu voudras initialiser un tableau dans une liste d'initialisation. Enfin il existe des solutions dégueulasses que tu trouveras très facilement en googlant, mais ce n'est pas moi qui vais te les donner parce que je refuse de promouvoir une programmation aussi sale tongue
Bref tu vas devoir de plus en plus utiliser des références pour éviter ces divers soucis. C'est un bon début d'ailleurs pour apprendre à bien gérer la mémoire smile
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

805

D'la merde, je vais pas allouer en RAM pour 64 octets grin

Non, j'va m'démerder, passer les S/Uint au constructeur, et lui faire initialiser le SDL_Rect comme le propose Jyaif. smile

806

Implémenté.

FYI : SDL_Rect m_offset = {offsetX, offsetY, width, height} marche très bien dans une méthode (et pas en liste d'init, et effectivement c'est très con)

807

Ha les exceptions, ou la deresponsabilisation la plus totale....
Et la liste d'init c'est un peu de la branlette de mamoutte pour pas grand chose, surtout dans ces cas!

808

Essaie m_offset((SDL_Rect){offsetX, offsetY, width, height}). Mais c'est du C99, donc en C++ c'est une extension GNU.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

809

Kevin -> J'y ai bien pensé, en pensant à ce que propose TIGCC, mais je voudrais éviter d'utiliser les extensions GNU...
JackosKing (./807) :
Ha les exceptions, ou la deresponsabilisation la plus totale....

Oui, mais le code est propre à l'oeil grin
JackosKing (./807) :
Et la liste d'init c'est un peu de la branlette de mamoutte pour pas grand chose, surtout dans ces cas!

Complètement ! Mais on fait comment pour s'en passer ? Je me prends une volée de bois vert de g++ si je le fais pas... sad

810

Folco (./806) :
FYI : SDL_Rect m_offset = {offsetX, offsetY, width, height} marche très bien dans une méthode (et pas en liste d'init, et effectivement c'est très con)

Heu si tu fais ça tu déclares une variable locale (tu voulais initialiser ta variable d'instance non?)
Bref pour moi la moins mauvaise des solutions serait de passer les 4 arguments au constructeur et de faire:
m_offset.width = width;
m_offset...
Ou alors tu passes un SDL_Rect et tu fais memcpy(&m_offset, &monRect, sizeof(monRect)) ou une copie membre à membre.
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741