begin process at 2012 05 30 07:38:02
  Trouver un code source :
 
dans
 
Accueil > Forum > 

C++ & C++ .NET

 > 

Divers

 > 

Divers

 > 

Question : Variables static/méthode static/initialisation


Derniers messages déposésPoser une question dans le forum ou lancer une discussion

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

Administrateur CodeS-SourceS
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 écrit

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...


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 écrit

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.


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 écrit

Ne serait-ce pas le design pattern "FlyWeight" dont tu aurais besoin ?


Je ne crois pas (voir en dessous).

"CptPingu" a écrit

Pourquoi 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

Administrateur CodeS-SourceS

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

Administrateur CodeS-SourceS
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

Administrateur CodeS-SourceS


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

1 2

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);    


Nos sponsors


Sondage...

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

Photothèque

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 7,457 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales