Accueil > Forum > > > > Question : Variables static/méthode static/initialisation
Question : Variables static/méthode static/initialisation
mercredi 11 mai 2011 à 11:17:47 |
Question : Variables static/méthode static/initialisation

Inutqen
|
Bonjour à tous, j'ai besoin d'un coup de main :)
J'ai un petit soucis avec un code C++, je suppose que la réponse à ma question se trouve quelque part sur le net, mais comme je ne sais pas exactement la source de l'erreur je ne sais pas où chercher.
Après avoir simplifié mon code à l'extrême, voilà ce que je veux faire :
Dans une class Class, je veux créer un conteneur static dans lequel sont stockés toutes les instances de Classe. De plus, mes instances de Classe sont créées dans une méthode static de la class Classe. Quand j'essaye d'accéder depuis une autre class à mon conteneur, les attributs de mes instances sont incohérents...
Parce qu'un code vaut mieux qu'un long discours :
Code C/C++ : Classe.h
#include <vector>
#include <iostream>
class Classe
{
public:
Classe(int);
static vector<Classe*> vect;
int nombre;
static void creerClasse();
}
Code C/C++ : Classe.cpp
#include Classe.h
std::vector<Classe*> Classe::vect;
using namespace std;
Classe::Classe(int nb)
{
nombre = nb;
vect.push_back(this);
}
void Classe::creerClasse()
{
Classe cl(1);
cout << vect.back()->nombre<<endl;
}
Code C/C++ : main.cpp
#include...
int main()
{
Classe::creerClasse();
cout<<Classe::vect.back()->nombre<<endl;
return 0;
}
L'affichage de nombre dans "creerClasse" donne 1, mais l'affichage de nombre dans le main donne n'importe quoi (4603319 par exemple).
Du coup le problème est facile à contourner, mais j'aimerais savoir la cause.
Merci !
|
|
mercredi 11 mai 2011 à 12:43:20 |
Re : Question : Variables static/méthode static/initialisation

pop70
|
Bonjour,
Y'a pas mal de trucs a revoir :
Pas de point virgule après la déclaration de classe, les cout et vector tout seul qui signifie qu'il doit y'avoir un using namespace quelque part avant, les membres déclarés public...
Sinon, pour ce qui est des membres statiques, s'ils sont là pour contenir les classes ou les compter, le plus simple est de les déclarer avec dans les fichiers pour y accèder, mais pas dans la classe.
Au final : (Reste juste à séparer dans différents fichier avec 2-3 #include)
#include <iostream>
#include <vector>
class Classe
{
public:
Classe(int);
int getNombre();
private :
int nombre;
};
static int nombreDeClasses = 0;
static std::vector<Classe*> toutesClasses;
Classe::Classe(int nb)
{
nombre = nb;
nombreDeClasses ++;
toutesClasses.push_back(this);
}
int Classe::getNombre()
{
return nombre;
}
int main()
{
Classe maClasse(21);
Classe maClasse2(2);
Classe maClasse3(384);
std::cout << "Il y a " << nombreDeClasses << " construite(s).\n";
for (int i = 0; i < toutesClasses.size(); i++)
{
std::cout << "\nLa classe " << i << " contient : " << toutesClasses.at(i)->getNombre();
}
std::cout << "\n\n";
return 0;
}
C++dialement,
Pop70
|
|
mercredi 11 mai 2011 à 13:16:42 |
Re : Question : Variables static/méthode static/initialisation

CptPingu
|
La réponse de pop70 étant très complète, je n'aurais que peu de chose à ajouter:
- Évite les "using namespace", voir: [ Lien ]
- Pourquoi as-tu besoin de faire cela ?
- Ne serait-ce pas le design pattern "FlyWeight" dont tu aurais besoin ?
________________________________________________________________________
Historique de mes créations, et quelques articles:
http://0217021.free.fr/portfolio
Merci d'utiliser Réponse acceptée si un post répond à votre question
|
|
mercredi 11 mai 2011 à 14:16:46 |
Re : Question : Variables static/méthode static/initialisation

Inutqen
|
Merci pour vos réponses.
"pop70" a écritY'a pas mal de trucs a revoir :
Pas de point virgule après la déclaration de classe, les cout et vector tout seul qui signifie qu'il doit y'avoir un using namespace quelque part avant, les membres déclarés public...
Le code écrit est un code rapidement écrit à la main, pas un copié collé, ce qui explique les oublis de namespace et de point virgule. Les membres déclarés public sont juste la pour simplifier à l'extrême, et donc ne pas écrire un getter.
"pop70" a écritSinon, pour ce qui est des membres statiques, s'ils sont là pour contenir les classes ou les compter, le plus simple est de les déclarer avec dans les fichiers pour y accèder, mais pas dans la classe.
mmmh, mais si c'est quelque chose dont je risque d'avoir besoin dans plusieurs autres classes (dont des classes pas encore codées), ce n'est pas plus simple de le mettre dans la classe, et d'y accéder ensuite de partout (quitte à mettre le conteneur en private et de faire un getter ?
Ton exemple fonctionne, mais ma question est plus de comprendre pourquoi ce que je fais ne fonctionne pas (ou est moche) plutôt que de faire fonctionner le code (y'a pleins de solutions pour ça).
"CptPingu" a écritÉvite les "using namespace"
Yep, c'est un autre problème a priori, mais merci pour le lien.
"CptPingu" a écritNe serait-ce pas le design pattern "FlyWeight" dont tu aurais besoin ?
Je ne crois pas (voir en dessous).
"CptPingu" a écritPourquoi as-tu besoin de faire cela ?
J'ai juste besoin d'un truc qui contient toutes les instances d'une classe. J'ai pris un vector pour l'exemple. Il me semblait que faire un membre static à l'intérieur de la classe était le moyen le plus propre (si ce n'est pas le cas je serais ravi d'apprendre pourquoi).
Le problème semble venir du fait que les appels au constructeur se font depuis une méthode static. Mais je ne comprends pas pourquoi, ni en quoi c'est moche...
|
|
mercredi 11 mai 2011 à 14:54:30 |
Re : Question : Variables static/méthode static/initialisation

CptPingu
|
Il me semblait que faire un membre static à l'intérieur de la classe était le moyen le plus propre (si ce n'est pas le cas je serais ravi d'apprendre pourquoi).
Ça dépend des cas. On évite généralement de faire des méthodes statiques de partout. Attention, néanmoins je pense personnellement que pour ce que tu cherches à réaliser, c'est une méthode propre, et je suis d'accord avec ton approche.
J'ai peut être encore mal compris ta question. Mais si tu cherches à avoir un élément qui est capable de garder une trace de toute classe créée, alors je te propose une méthode générique et non intrusive pour le faire.
Il te suffit d'hériter de la classe GenericAutoRef, et lors d'un appel à showInstance<TaClasse>(), tu vois la liste de ces classes. (Utilisation du CRTP => Cf Google > "Curiously Recurring Template Pattern").
A toi ensuite d'adapter showInstance pour faire ce que tu veux avec les classes.
Code C/C++ :
#include <iostream>
#include <list>
template <typename T>
class GenericAutoRef
{
public:
typedef typename std::list<T*>::iterator iterator;
GenericAutoRef() { _tab.push_back(static_cast<T*>(this));}
~GenericAutoRef() { _tab.remove(static_cast<T*>(this));}
static iterator begin() { return _tab.begin(); }
static iterator end() { return _tab.end(); }
private:
static std::list<T*> _tab;
};
template <typename T>
std::list<T*> GenericAutoRef<T>::_tab;
class Class : public GenericAutoRef<Class>
{
public:
Class(int i) : _i(i) {}
virtual ~Class() {}
int get() const { return _i;}
private:
const int _i;
};
template <typename T>
void showInstance()
{
std::cout << "Dump:" << std::endl;
int nb = 0;
for (typename GenericAutoRef<T>::iterator it = GenericAutoRef<T>::begin();
it != GenericAutoRef<T>::end(); ++it)
{
std::cout << *it << std::endl;
++nb;
}
std::cout << "Nb class = " << nb << std::endl;
}
int main()
{
showInstance<Class>();
Class* cl1 = new Class(1);
showInstance<Class>();
Class* cl2 = new Class(2);
showInstance<Class>();
Class* cl3 = new Class(3);
showInstance<Class>();
{
Class cl4(4);
showInstance<Class>();
}
showInstance<Class>();
delete cl1;
showInstance<Class>();
delete cl2;
showInstance<Class>();
delete cl3;
showInstance<Class>();
return 0;
}
________________________________________________________________________
Historique de mes créations, et quelques articles:
http://0217021.free.fr/portfolio
Merci d'utiliser Réponse acceptée si un post répond à votre question
|
|
mercredi 11 mai 2011 à 14:58:11 |
Re : Question : Variables static/méthode static/initialisation

Inutqen
|
Merci, je regarde ça tout de suite.
Une idée de la raison du pourquoi du comment mon code plante ? 
|
|
mercredi 11 mai 2011 à 15:16:20 |
Re : Question : Variables static/méthode static/initialisation

CptPingu
|
Réponse acceptée !
Pour ton exemple:
Dans "creerClasse()", tu crées un objet en local temporaire, qui est détruit au sortir de la fonction.
Donc forcément, la valeur va être fausse si tu essaies de la lire après sa destruction.
Si tu avais fait un "new Class", ce souci n'aurait pas eu lieu.
________________________________________________________________________
Historique de mes créations, et quelques articles:
http://0217021.free.fr/portfolio
Merci d'utiliser Réponse acceptée si un post répond à votre question
|
|
mercredi 11 mai 2011 à 15:26:06 |
Re : Question : Variables static/méthode static/initialisation

Inutqen
|
Merci pour le GenericAutoRef, ça fait ce je veux.
Par contre pour la raison du plantage de mon code je ne comprends toujours pas.
Si dans "creerClasse()" je fais :
Classe cl(1);
vect.push_back(&cl);
(c'est-à-dire que je met à jour le vector dans creerClasse() et pas dans le constructeur)
ça marche.
Or cl devrait être détruit aussi, non ?
|
|
mercredi 11 mai 2011 à 15:34:14 |
Re : Question : Variables static/méthode static/initialisation

CptPingu
|
Classe cl(1);
vect.push_back(&cl);
(c'est-à-dire que je met à jour le vector dans creerClasse() et pas dans le constructeur)
ça marche.
Si tu avais fait: vect.size() tu aurais eu le bon nombre malgré que tu ais eu un élément corrompu.
Or ici, tu prends l'adresse de cl que tu ajoutes en fin de vecteur. cl est détruit et donc l'élément en fin de vecteur est un pointeur qui pointe sur un élément détruit. Cet élément du vecteur (le pointeur) est toujours dans le vecteur.
Quand tu fais back(), tu récupères cet élément, et tu essaies de regarder dedans, d'ou un nombre incorrect (d'ailleurs ça peut aussi planter, puisque l'accès à un élément désallouer est indéfini).
________________________________________________________________________
Historique de mes créations, et quelques articles:
http://0217021.free.fr/portfolio
Merci d'utiliser Réponse acceptée si un post répond à votre question
|
|
mercredi 11 mai 2011 à 15:40:06 |
Re : Question : Variables static/méthode static/initialisation

pop70
|
Réponse acceptée !
En reprenant le code de départ, et en affichant juste les variables ainsi que leurs
adresses, on voit bien que le problème vient de la portée de l'objet comme l'a dit CptPingu :
Avec le code suivant :
Code C/C++ :
#include <vector>
#include <iostream>
using namespace std;
class Classe
{
public:
Classe(int);
static vector<Classe *> vect;
int separateur;
int nombre;
static void creerClasse();
};
std::vector<Classe*> Classe::vect;
using namespace std;
Classe::Classe(int nb)
{
nombre = nb;
cout << "\n\tLOCALISATION : Constructeur de classe\n";
cout << "\n[DEBUG] 'nombre' dans constructeur de Classe() : " << nombre;
printf("\n[DEBUG] @'nombre' dans constructeur de Classe() : 0x%08x",
&nombre);
printf("\n[DEBUG] @'cl' dans constructeur de Classe() : 0x%08x\n", this);
vect.push_back(this);
}
void Classe::creerClasse()
{
cout << "\n\tLOCALISATION : 'creerClasse()'\n";
Classe cl(126);
cout << "\n\tLOCALISATION : 'creerClasse()'\n";
cout << "\n[DEBUG] 'nombre' dans creerClasse() : " << vect.back()->nombre;
printf("\n[DEBUG] @'nombre' dans creerClasse() : 0x%08x",
&vect.back()->nombre);
printf("\n[DEBUG] @'cl' dans creerClasse() : 0x%08x\n", &cl);
}
int main()
{
Classe::creerClasse();
cout << "\n\tLOCALISATION : 'main()'\n";
cout << "\n[DEBUG] 'nombre' dans main() : " << Classe::vect.back()->nombre;
printf("\n[DEBUG] @'nombre' dans main() : 0x%08x",
&Classe::vect.back()->nombre);
printf("\n[DEBUG] @'cl' dans main() : 0x%08x", Classe::vect.back());
printf ("\n[DEBUG] @'cl' dans main() en decimal : %d", Classe::vect.back());
cout << "\n\n";
return 0;
}
La console affiche ceci :
Code :
LOCALISATION : 'creerClasse()'
LOCALISATION : Constructeur de classe
[DEBUG] 'nombre' dans constructeur de Classe() : 126
[DEBUG] @'nombre' dans constructeur de Classe() : 0x0022ff3c
[DEBUG] @'cl' dans constructeur de Classe() : 0x0022ff38
LOCALISATION : 'creerClasse()'
[DEBUG] 'nombre' dans creerClasse() : 126
[DEBUG] @'nombre' dans creerClasse() : 0x0022ff3c
[DEBUG] @'cl' dans creerClasse() : 0x0022ff38
LOCALISATION : 'main()'
[DEBUG] 'nombre' dans main() : 2293560
[DEBUG] @'nombre' dans main() : 0x0022ff3c
[DEBUG] @'cl' dans main() : 0x0022ff38
[DEBUG] @'cl' dans main() en decimal : 2293560
Or ce qui saute aux yeux, c'est que le nombre récupéré dans le main est en fait l'adresse mémoire de la cl !
J'ai d'ailleurs rajouté une variable nommée "séparateur" juste avant la déclaration de nombre pour pouvoir distinguer l'adresse de nombre de l'adresse de la classe. Il faut à mon avis en effet faire un "new Classe" comme l'a dit CptPingu.
Donc rien d'aléatoire (ou presque) dans la valeur "nombre" qui sort dans le main()
Pop70
|
|
Cette discussion est classée dans : nombre, code, class, static, classe
Répondre à ce message
Sujets en rapport avec ce message
Surdéfinition statique (static) d'une variable membre [ par PetersonG ]
Bonjour,Une drôle d'idée m'a fait surdéfinir en static une variable membre d'une classe parente, et, à ma grande surprise, le code compile sans problè
Mélanger code managé et non managé [ par fred_82 ]
Bonjour,Je souhaiterais mélangé du code managé et du code non managé mais je n'y arrive pas.pour avoir un classe non managé, il suffit pourtant de cré
Conception d'une classe [DEBUTANT ] [ par Nixeus ]
Bonjour,Un problème surement de conception de classe me fait perdre la tete, je vais m'expliquer le plus simple possible:class A{ int m_
classe [ par cyrinelahsini ]
Salut, j'ai défini deux classes : class tableau et class chaine. dans la class chaine, j'ai défini une fonction chtab qui convertitune chaine en un ta
Windows plante {je sais pas nouveau } pour l'execution du mon code [ par darkwhite ]
Salut a tous Je debute en C, et j'ai commencer a faire un petit programme. A la moitié de la creation je l'essaie mé windows me sort un message derreu
Problème de d'utilisation d'une Dll avec un exe [ par pca06 ]
Bonsoir, Je dois utiliser les fonctionnalités d'une Dll dans un application écrite en C. La Dll est constituée d'un classe C++ exportée. J'ai déclaré
illegal call of non-static member function [ par Zootella ]
Hello all, J'ai une classe qui comprend une fonction static, jusque là pas de problémes, mais quand j'esseye d'appeler une fonction de la même classe
Interaction entre objets [ par kharrat ]
Salut,Je cherche à implémenter une relation d'association 1-1 entre 2 objets de 2 classes différentes.Mon code:---------------------------------------
Random GMP [ par chewbaka62 ]
Bonjour,Voici un code qui devrait (en principe) me générer un très grand nombre aléatoire ( compris entre 0 et 2^n-1). Le problème, c'est que chaque f
erreur variable dans une classe [ par pumab12 ]
voila jai un probleme :: class SPEC Player : public Unit{ friend class WorldSession; public: explicit Player (WorldSession *session);
Livres en rapport
|
Derniers Blogs
POUR RAPPEL ! LES SPéCIFICATIONS DES PROTOCOLES OFFICE ET SHAREPOINT SONT DISPONIBLES SUR MSDNPOUR RAPPEL ! LES SPéCIFICATIONS DES PROTOCOLES OFFICE ET SHAREPOINT SONT DISPONIBLES SUR MSDN par neodante
Quelle est le point commun entre : Microsoft il y a 10 ans et Apple aujourd'hui ? Réponse: avoir une politique de protocoles propriétaires et fermés :) Car pour rappel (si si je vous assure c'est important de le rappeler), la majorité des spécifications e...
Cliquez pour lire la suite de l'article par neodante JOYEUX ANNIVERSAIRE NIXJOYEUX ANNIVERSAIRE NIX par ebartsoft
Souhaitons un bon et joyeux anniversaire à notre hôte à tous, Nix.
Je ne le répéterais jamais assez mais sans lui rien ne serait possible. Il défit en permanence les lois de la gravité et comme il le dit si bien, si tu lui fais confiance ça devra...
Cliquez pour lire la suite de l'article par ebartsoft IMAGINE CUP 2012, MAKE A SIGN EN FINALEIMAGINE CUP 2012, MAKE A SIGN EN FINALE par junarnoalg
Voilà qui est fait, la nouvelle est officielle ! L'équipe belge "Make a Sign" va au pays des kangourous défendre son projet dans la catégorie Software Design. http://www.imaginecup.com/CompetitionsContent/Competition/WorldwideFinalists.aspx V...
Cliquez pour lire la suite de l'article par junarnoalg KINECT 1.5 IS OUT !KINECT 1.5 IS OUT ! par Vko
La version 1.5 du Kinect For Microsoft vient tout juste de sortir ! Plein de nouveautés: Tracking de squelette en Near Mode Détection en position assise Détection faciale avec un SDK dédié Documentation et des guideline (enfin) Un out...
Cliquez pour lire la suite de l'article par Vko LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) par richardc
Mise à jour des Web API du 14 Mai
Réservez dès maintenant votre journée du 20 juin pour le Windows Azure Dev Camp 2012 à Paris
Mise à jour de Team Foundation Service
MechCommander 2 sur Windows 8
Entity Framework 5 Release Candidate e...
Cliquez pour lire la suite de l'article par richardc
Forum
MATLAB PROGRAMME MATLAB PROGRAMME par wahab1087
Cliquez pour lire la suite par wahab1087 RGB2GRAYRGB2GRAY par musa18
Cliquez pour lire la suite par musa18
Logiciels
sDEVIS-FACTURES vlPRO (8.1.0.3)SDEVIS-FACTURES VLPRO (8.1.0.3)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO 974 Application Server (12.2.4.6)974 APPLICATION SERVER (12.2.4.6)Développez de puissantes applications dans un environnement de 'cloud computing', clusterisé, séc... Cliquez pour télécharger 974 Application Server vPicture (1.4.2.1)VPICTURE (1.4.2.1)Avec vPicture, hébergez vos images facilement et rapidement.
vPicture est un utilitaire simple, ... Cliquez pour télécharger vPicture Easy-Planning (2.2.1.6)EASY-PLANNING (2.2.1.6)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté au... Cliquez pour télécharger Easy-Planning COM-BACKUP (2.0)COM-BACKUP (2.0)
COM-BACKUP est un logiciel de sauvegarde qui permet de planifier les sauvegardes de vos dossiers ...
Cliquez pour télécharger COM-BACKUP
|