Registration automatique d'objets globaux

Registration automatique d'objets globaux - C++ - Programmation

Marsh Posté le 24-07-2007 à 21:52:28    

Bonjour,
Je ne poste pas souvent ici, mais là je me suis désespérer et je me suis qu'un gourou du forum pourrait peut être m'aider.
Je développe un framework ou les classes se registre toute seule dans une factory. Pour faire ceci j'utilise des variables globales qui sont le code de registration dans le constructeur.
J'ai reproduit le principe dans un petit exemple recopier ci-dessous.
 
Tout ceci marche très bien si tout se trouve dans un seul projet (.exe).
Hors actuellement je suis en train de faire des librairies pour le kernel et là ça ne marche plus.
Le compilateur (Visual studio 2005) supprime les variables globales de la librairie car elles ne sont pas utilisées dans le main (ce qui est normal). Et je voudrais donc trouver un truc pour "grugger" le compilateur.
Je pensais avoir trouver en incrémentant une variable globale utiliser par le main(). Mais il se trouve que Visual à un comportement bizarre dans ce cas.
En effet, dans l'exemple ci-dessous, uniquement les 3 variables globales présent dans le fichier MyLib.cpp sont "registrées". Car le compteur est défini dans le fichier. Dans MyLib2.cpp Visual supprimer mes 2 variables globales...
 
Ceux qui veulent essayer de compiler le tout, il faut mettre MyLib.cpp et MyLib2.cpp dans un librairie statique. Et Exe.cpp dans un application console où l'on inclue la librairie statique.
 

Code :
  1. //----------------------------------------------------------------------------------------------------------------------
  2. //! \file  MyLib.h
  3. //----------------------------------------------------------------------------------------------------------------------
  4. extern int g_iCount;
  5. class keCAutoRegister
  6. {
  7. public:
  8. keCAutoRegister(int a_iCount)
  9. {
  10.  printf("%d\n", a_iCount);
  11.  ++g_iCount;
  12. }
  13. };
  14. #define keRegisterObject(x_Object, x_Value) keCAutoRegister x_Object(x_Value);


Code :
  1. //----------------------------------------------------------------------------------------------------------------------
  2. //! \file  MyLib.cpp
  3. //----------------------------------------------------------------------------------------------------------------------
  4. #include <stdio.h>
  5. #include "MyLib.h"
  6. int g_iCount = 0;
  7. keRegisterObject(g_oGlobalInstance1, 6);
  8. keRegisterObject(g_oGlobalInstance2, 2);
  9. keRegisterObject(g_oGlobalInstance3, 20);


Code :
  1. //----------------------------------------------------------------------------------------------------------------------
  2. //! \file  MyLib2.cpp
  3. //----------------------------------------------------------------------------------------------------------------------
  4. #include <stdio.h>
  5. #include "MyLib.h"
  6. keRegisterObject(g_oGlobalInstance9, 5);
  7. keRegisterObject(g_oGlobalInstance8, 0);


Code :
  1. //----------------------------------------------------------------------------------------------------------------------
  2. //! \file  Exe.cpp
  3. //----------------------------------------------------------------------------------------------------------------------
  4. #include <stdio.h>
  5. #include "MyLib.h"
  6. extern int g_iCount;
  7. int main()
  8. {
  9. printf("Nb: %d\n", g_iCount);
  10. return 0;
  11. }


 
Lorsque l'on exécute le code on obtient :

6
2
20
Nb: 3


 
Si je passe "int g_iCount = 0;" de MyLib.cpp à MyLib2.cpp, on obtient ceci :

5
0
Nb: 2


 
Et moi, je souhaiterais avoir (peu importe l'ordre de déclaration) :

6
2
20
5
0
Nb: 5


 
Merci à ceux qui m'ont lu. J'attends vos conseils avisés.
Pour informations ce code marche très bien sous Codewarrior. Sous gcc, je vais le tester dès ce soir.
Je suis donc à la recherche de solution "Microsoft specific". Via les __declspec() et cie.


Message édité par leander le 24-07-2007 à 22:58:00
Reply

Marsh Posté le 24-07-2007 à 21:52:28   

Reply

Marsh Posté le 24-07-2007 à 21:55:27    

Faudrais voir à utiliser un singleton qui géres tout ça de manière centralisé en créant des instances dynamiques de tes variables globales.

Reply

Marsh Posté le 24-07-2007 à 22:05:21    

Je ne suis pas sur que ça résoudre mon problème. Mon idée est que je rajouter un fichier avec une classe avec une macro de registration dans le .cpp, et lorsque je lance l'exe, la classe soit automatiquement registrée dans ma factory. Sans avoir à modifier aucun autre fichier.
 
Sinon, j'ai fais un test sous, gcc est j'ai le même comportement que sous Visual Studio.
C'est triste à dire, mais vive Codewarrior...

Reply

Marsh Posté le 24-07-2007 à 22:27:42    

conseil de qualitay:
 
MyLib.h:
extern int g_iCount1;
extern int g_iCount2;
 
MyLib1.cpp
int g_iCount1 = 0;
register...
 
MyLib2.cpp
int g_iCount2 = 0;
register...
 
Ca te bouffe un int en mémoire mais pense a tout le temps que tu auras économisé.
Non ne me remercie pas :)

Reply

Marsh Posté le 24-07-2007 à 22:33:13    

jojolepingouin, c'est pas vraiment ça que je recherche comme solution. Ma classe de registration est unique (elle ne peut donc accéder qu'a un int) et elle sera utilisé par tous les cpp (plusieurs dizaines voir centaines).
 
Et ça veut dire que je dois faire un extern dans le main par .cpp. Ce qui est exactement le contraire de ce que je recherche.

Reply

Marsh Posté le 24-07-2007 à 22:53:42    

n'empeche, ton code (sans rien toucher) chez moi ca marche :)
 
rene@moumachine ~/eclipse/code $ ./main  
5
0
6
2
20
Nb: 5
 
du coup je vais pas pouvoir t'aider plus que ca....
 
edit: si j'ai du virer ca du main :extern int g_iCount; sinon ca compilait pas.


Message édité par jojolepingouin le 24-07-2007 à 22:54:51
Reply

Marsh Posté le 24-07-2007 à 22:54:32    

Salut,
 
Tout d'abord, vire ces variables globales, c'est pas beau du tout ;)
Ensuite, fait comme te l'a dit Joel F, utilise un singleton. Ainsi, tes objets pourront simplement appeller un code du style:

Code :
  1. MaFactory::getInstance().register(this, TonIdentifiantDobjet);


 
Enfin, mauvaise cat', le C, c'est à côté (oui, y'a un 'class' et un 'public', mais c'est les 2 seules chose C++ ici).
 
Ah, et dernier point, évites de mettre le copyright de ta boîte, ça fait mauvais genre :/

Reply

Marsh Posté le 24-07-2007 à 23:02:27    

En effet, pour le copyright, j'avais pas vu, merci. Mais j'ai rien à cacher, mais c'est vrai qu'il vaut mieux éviter ;)
 
Sinon, pour ta solution ca marche en effet, mais c'est pas le but rechercher. La registration comme tu la proposes, elle doit se faire dans le main ou une fonction appeler par le main.
Hors je souhaite que la registration se fasse automatique lorsqu'un .cpp se trouve dans un projet. Ca peut paraitre non courant, mais c'est super pratique et j'utilise cette méthode depuis plus de 5 ans.
 
Les seules solutions qui me conviendront seront celle ou les registrations se feront comme ceci dans un .cpp:

Code :
  1. keRegisterObject(g_oGlobalInstance9, 5);


 
La solution doit donc venir d'une modification dans la macro keRegisterObject() ou la classe keCAutoRegister et son constructeur.
Jusqu'a présent j'avais une solution spécifique pour Codewarrior et sous windows je ne faisais pas de librairie.
Mais j'aimerais vraiment pouvoir faire des librairies et c'est pour cela que je cherche un solution spéficique windows (et gcc aussi remarque...) ou générique.


Message édité par leander le 24-07-2007 à 23:04:26
Reply

Marsh Posté le 25-07-2007 à 00:46:03    

J'ai fait un truc approchant il y a qques temps si je me rappelle bien.
tu peux essayer avec un truc genre créer une fonction d'enregistrement qui retourne un bool et dans tes cpp faire :

Code :
  1. namespace { const bool foo = RegisterFunc(pouet, 9); }


avec un petit define pour enrober le tout ça devrait le faire.
Je faisais ça sous VC6 pour une factory et ça marchait.
[edit] avec un singleton c'est encore mieux quand même.


Message édité par SquiZZ le 25-07-2007 à 00:47:17
Reply

Marsh Posté le 25-07-2007 à 09:31:50    

SquiZZ, en fait, le principe est à peu pres le meme que celui que le propose. Ca marche très bien si les fichiers sont tous au sein d'un projet executable.
Mais dès que l'on met ceci dans une library, le probleme est le meme. Le code est supprimé.
 
Mais merci pour ta réponse, ca va dans le sens de ce que je recherche.
 
Pour le singleton, j'en ai un pour ma factory bien sur. Mais pour la registration, je prefere une registration automatique plutot qu'une manuelle appelé d'une façon ou d'une autre via le main. C'est beaucoup plus souble pour le développement en équipe et en multiplateforme.

Reply

Marsh Posté le 25-07-2007 à 09:31:50   

Reply

Marsh Posté le 25-07-2007 à 13:11:55    

mais elle est pas automatique puisque tu appelles ta macro (que tu peux récrire pour faire appel a un singleton)

Reply

Marsh Posté le 25-07-2007 à 13:57:26    

Ma macro est écrit dans un cpp en dehors de toutes fonctions. Si tu arrives à faire la même chose avec un singleton, je suis preneur.
 
D'ailleurs, dans mon framework, mon code de base appelle un singleton (dans le constructeur de keCAutoRegister). Le problème n'est pas comment faire l'appel (via un singleton ou une fct C, etc.), mais que du code, mis dans un .cpp soit exécuté au lancement de l'application sans que j'ai à faire de référence sur ce code depuis d'autre cpp. Et ceci, lorsque le code se trouve dans un .lib (car dans un executable ça marche déjà).

Reply

Marsh Posté le 25-07-2007 à 15:50:56    

Le problème c'est donc que le programme n'utilise pas de code présent dans les librairies statiques donc elles ne sont pas incluses pendant le linkage.
A part mettre une fonction InitLibTotoxxx dans chaque lib et l'appeler depuis le main je vois pas de solution.

Reply

Marsh Posté le 25-07-2007 à 19:29:05    

SquiZZ, c'est en effet exactement ça mon problème.

Reply

Marsh Posté le 25-07-2007 à 23:36:55    

leander a écrit :

C'est beaucoup plus souble pour le développement en équipe et en multiplateforme.


En multiplateforme ? la preuve dans ce fil.
 
Cette technique peut éventuellement fonctionner en créant un DSO au lieu d'une bibliothèque statique.

Reply

Marsh Posté le 26-07-2007 à 09:03:15    

C'est quoi un DSO ?
 
Pour le multiplateforme, s'il y a une solution générique tant mieux. Sinon, il y a toujours la solution de ne pas utiliser de librarie.

Reply

Marsh Posté le 26-07-2007 à 14:47:57    

C'est une bibliothèque partagé (comme un .dll/win, .so/unixoide ou .dynlib pour osx je crois), mais google t'en dira plus que moi.
J'utilise assez régulièrement cette méthode, je scanne avec la factory les "plugins" pour voir si je peux obtenir un objet du type attendu; si c'est le cas, je l'enregistre, sinon, j'ignore la bibliothèque. Je ne sais pas si c'est à ça que ++fab pensait, mais je ne connais pas vraiment d'autres façons en fait :)

Reply

Marsh Posté le 27-07-2007 à 14:49:47    

et avec un static ca marche pas ?

Code :
  1. #define keRegisterObject(x_Object, x_Value) static keCAutoRegister x_Object(x_Value);

Reply

Marsh Posté le 11-08-2007 à 18:51:11    

non une static ne marche pas.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed