Salut, *** Avant toute chose : mettez à jour votre dépôt SubVersion local, j'ai changé un paquet de fichiers !!! ***
*** Email un peu long mais c'est pour expliquer en profondeur un problème de Wormux vieux de 4 ans au moins *** J'ai enfin fait le grand pas : j'ai écrit la classe qui va gérer des singletons. En deux mots, c'est des instances qui vont être créer lorsqu'on y accède. L'avantage est qu'on contrôle la création de l'instance, et qu'on peut ajouter des bouts de code (ex: vérifier que SDL est lancé avant de charger une image!). D'ailleurs j'ai trouvé une erreur: ImagesParSeconde instanciait un objet Text qui a besoin d'une Font qui était créée ... avant l'initilisation de SDL et TTF !!! (mais apparement, ça marchait quand même :-P). J'ai donc supprimé toutes les variables globales big_font, small_font, etc. et j'ai remplacé ça par : global().small_font() (il faut un #include "../include/global.h"). Le désavantage est que ça ajoute deux déréférencement de pointeur et deux if pour chaque accès aux variables (un if pour être exact, l'autre est une assertion => désactivée en mode non debug). Bon, je pense que ça coûte rien du tout au niveau des performances et vous verrez après (dans mon email) tous les avantages. L'autre soucis est que si on met tout ce qui doit être instancié dans "Global", la compilation d'un seul fichier demandera l'ensemble des fichiers d'entêtes (.h) ... ce qui risque d'être plutôt lourdingue (ralentir la compilation quoi). Une solution plus soft serait de faire une classe "Global" pour chaque type d'objet (ex: Font, Graphic, Game, ... enfin, il faudrait en discuter). À terme, la majorité des variables globales devraient utiliser des singletons (je pense). Par contre, pour certains classes "critiques", c'est peu/pas envisageable. Je pense notamment à Config qui est utilisé à peu près partout dans le jeu ... --- Quelques problèmes résolus avec les singletons : - Le problème des dépendences sont supprimés. Je m'explique : avant, tout était en variable globale. Le gros problème est que les objets sont instanciés l'un après l'autre. Mais que se passe-t-il lorsque A utilise B alors que B n'est pas encore instancié ? Ben le compilateur ne dit rien, et souvent ça passe. Mais ça arrive que ça plante ! Exemple : en modifiant Config::Config() pour ajouter ttf_filename, j'ai utilisé DEFAULT_DATADIR. Mais ... ça plantait lamentablement du côté de std::string !? Après une bonne heure j'ai compris le problème : DEFAULT_DATADIR n'existait pas encore ! Gloups ! J'espère que vous voyez le problème. J'ai rencontré ce problème très très souvent. Un autre au hasard : Time::Time() accédé avant sa création (renvoyait n'importe quoi donc). - On contrôle enfin quand l'objet est détruit. Avant, les bibliothèques étaient désactivées (SDL_Quit & Cie, et avant l'équivalent pour ClanLib), et seulement après les objets étaient détruits. Le problème est que la destruction a besoin de la bibliothèque (ex: l'informer de la destruction de l'objet). Et fatalement : ça plante. J'ai eu ce problème très récement : Font::~Font() qui appelait TTF_CloseFont() *après* TTF_Quit(). (*bug corrigé*) Hum, il doit y avoir d'autres avantages, mais je ne vois pas trop là tout de suite. J'espère que je vous ai convaincu de l'utilité de mon dernier patch de 1000 lignes :-P Victor -- Victor Stinner - étudiant à l'UTBM (Belfort, France) http://www.haypocalc.com/wiki/Victor_Stinner
