[C++] constructeur et variable statique

Résolu/Fermé
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 - 9 févr. 2010 à 08:44
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 - 17 févr. 2010 à 13:03
Bonjour,
voilà mon souci, j'ai défini une classe avec un membre statique et un constructeur qui modifie cette variable.
exemple :
class mots
{
  static std::vector<std::string> list
 public:
  mots(std::string a){list.push_back(a);}
}

J'appel ce constructeur dans pleins d'unité de compilation :
machin.cpp:
mots m_machin("test");

donc voilà, en toute théorie, avant le main je rempli la variable mots::list avec des mots passer en paramètre de constructeur. Mais en pratique, si je demande l'affichage de cette liste dans le main(), je trouve qu'elle est vide. Et pourtant un affichage dans le constructeur me montre bien que la variable est rempli, mais elle semble détruite à chaque fin de constructeur. Si quelqu'un pouvait m'éclairer sur ce problème.

Le but de ceci est de récupérer des listes de mots qui sont réparties sur une cinquantaine de fichiers dans une seul variable pour un affichage structuré. Donc si vous avez une autre solution, je suis preneur.
Merci.

15 réponses

Bonjour,

Tu as une classe Mots contenant une liste de mots.
Mais la liste ne contiendra toujours qu'UN SEUL mot, car seul le constructeur y ajoute quelque-chose. Çà ne sert pas à grand chose...

Pour créer ta liste de mots, comment fais-tu ?
T'as pas de méthode ajouterMot pour ajouter un mot dans la liste ?

De plus, que signifie "avant le main je rempli la variable mots" ? AVANT le main ? Comment fais tu ?

Bref, soit je n'ai pas compris grand chose à ta question,
Ou soit tu n'a pas compris grand chose à la programmation objet.

En espèrant t'avoir aidé...
0
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
9 févr. 2010 à 14:12
@Char Sniper: Pour commencer j'utiliserais un std::set<std::string> pour stocker les mots, ce qui évitera les problèmes liés aux doublons, permettra un accès en O(log(n)) (au lieu de O(n) pour vérifier la présence ou non d'un mot dans la "liste").

@swed : non sa "liste" contiendra bien plusieurs mots, c'est tout l'intérêt d'un membre statique : celui-ci est commun à toutes les instances de la classe "mots".

@Char sniper : peux-tu nous donner un exemple de code minimal ? Pour accéder à ton membre statique, il faut soit un accesseur (static) soit y accéder en tant que tel. Je ne peux pas tester dans l'immédiat mais ça ressemble à ça :

#include <set>
#include <string>
#include <iostream>

class mots_t{
  public:
    typedef std::set<std::string> list_t;

  protected:
    static list_t list;

  public:
    mots(const std::string & mot){
      list.insert(mot);
    }

    inline static const list_t & get_list() const{
      return list;
    }
};

int main(){
  mots_t mots1("pouet");
  mots_t mots2("plop");
  
  // Accès à mots_t::list
  const mots_t::list_t & list = mots_t::get_list();

  // Afficher les mots
  mots_t::list_t::const_iterator
    mots_it (list.begin()),
    mots_end(list.end());
  for(;mots_it!=mots_end;++mots_it) std::cout << *mots_it << std::endl;
  return 0;
}


Ceci dit je ferais plus simplement :

#include <set>
#include <string>
#include <iostream>

typedef std::set<std::string> mots_t;

/*
// ou encore :

class mots_t : public std::set<std::string> {
 //...
};
*/

int main(){
  mots_t.insert("plop");
  mots_t.insert("pouet");

  // Afficher les mots
  mots_t::const_iterator
    mots_it (mots.begin()),
    mots_end(mots.end());
  for(;mots_it!=mots_end;++mots_it) std::cout << *mots_it << std::endl;
  return 0;    
}


Bonne chance
0
loupius Messages postés 697 Date d'inscription dimanche 1 novembre 2009 Statut Membre Dernière intervention 31 décembre 2017 148
9 févr. 2010 à 14:38
#include <string>
#include <vector>
#include <cstdlib>
#include <iostream>

class Mots
{
  public:
    static std::vector<std::string> liste;
    Mots(std::string a) { liste.push_back(a); }
};

std::vector<std::string> Mots::liste;

void unDePlus(std::string str)
{
  Mots mot(str);
}

int main(int argc, char *argv[])
{
  unDePlus("table");
  unDePlus("chaise");
  unDePlus("fauteuil");
  for (unsigned int i=0; i<Mots::liste.size(); i++)
    std::cout << Mots::liste[i] << std::endl;
  return EXIT_SUCCESS;
}
Cette réponse te convient-elle ?
Bonne continuation.
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
9 févr. 2010 à 14:47
Salut.
Merci pour ton intervention mamiemando. Le set, ça peut être pas mal, mais la rapidité, je m'en fiche un peu. Je regarderai plus en détail ce que tu proposes.
Voici un code minimal qui présentera le problème : (c'est crade, mais c'est juste du test)
main.cpp :
#include <vector>
#include <string>
#include <iostream>
std::vector<char*>l;
struct A
{
  A(char *a){l.push_back(a);std::cout<<a<<" constructeur\n";}
};
A a("essai");
A b("essa2i");
int main()
{
     std::cout<<l.size()<<"\n";// devrai rendre 4
    return 0;
}

et un fichier machin.cpp :
#include <vector>
#include <iostream>
extern std::vector<char*> l;
struct A{A(char* A);};
A c("dkjf");
A d("flgkfd");
void lisdf()
{ 
       return;
}

le problème semble venir de la STL, car après multiple essai, je me suis orienté vers une liste chainé qui fonctionne (mais autrement plus dur à mettre en oeuvre). Dans tout les cas, j'aimerai bien comprendre ce qui se passe.
Dans ce code minimal, seul a et b sont pris en compte dans la liste.
Je ne peux pas mettre les variables c et d dans la fonction lisdf(), car je ne suis pas sur que cette fonction sera appelé, mais j'ai quand même besoin de récupérer la donnée.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
10 févr. 2010 à 02:26
Le set, ça peut être pas mal, mais la rapidité, je m'en fiche un peu

Ce n'est pas qu'un problème de rapidité, dans ton code tu peux insérer le même mot en plusieurs exemplaires,

devrait rendre 4

Non c'est normal que ça retourne 2,

Le problème semble venir de la STL

Un peu de sérieux :-),

Je me suis orienté vers une liste chainé qui fonctionne (mais autrement plus dur à mettre en oeuvre)

Les classes std::list et std::vector ont toutes deux une méthode push_back, je ne vois pas la différence.

Dans ce code minimal, seul a et b sont pris en compte dans la liste.
Je ne peux pas mettre les variables c et d dans la fonction lisdf(), car je ne suis pas sur que cette fonction sera appelé, mais j'ai quand même besoin de récupérer la donnée.


Pas compris.

Voici le code que j'ai posté corrigé (je n'avais pas de quoi tester la dernière fois) :

#include <set>
#include <string>
#include <iostream>

class mots_t{
  public:
    typedef std::set<std::string> list_t;

  protected:
    static list_t list;

  public:
    mots_t(const std::string & mot){
      list.insert(mot);
    }

    inline static const list_t & get_list() {
      return mots_t::list;
    }
};

mots_t::list_t mots_t::list = mots_t::list_t();

int main(){
  mots_t mots1("pouet");
  mots_t mots2("plop");

  // Accès à mots_t::list
  const mots_t::list_t & list = mots_t::get_list();

  // Afficher les mots
  mots_t::list_t::const_iterator
    mots_it (list.begin()),
    mots_end(list.end());
  for(;mots_it!=mots_end;++mots_it) std::cout << *mots_it << std::endl;
  return 0;
}


et :

#include <set>
#include <string>
#include <iostream>

typedef std::set<std::string> mots_t;

/*
// ou encore :

class mots_t : public std::set<std::string> {
 //...
};
*/

int main(){
  mots_t mots;
  mots.insert("plop");
  mots.insert("pouet");

  // Afficher les mots
  mots_t::const_iterator
    mots_it (mots.begin()),
    mots_end(mots.end());
  for(;mots_it!=mots_end;++mots_it) std::cout << *mots_it << std::endl;
  return 0;
}


Bonne chance
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
10 févr. 2010 à 08:11
Merci, le problème, c'est que ta solution ne répond pas à mon problème.
Pourquoi est-ce normal que ça rende 2 ? J'ai fait appel 4 fois au constructeur (2 fois dans chaque fichier), la liste devrais donc avoir 4 comme taille. Quand je dit que le problème viens de la STL, c'est que ma liste semble réinitialisé entre les deux fichier (d'où une taille de 2). Alors que si j'utilise une liste chainé afin de gérer directement ce que je fait, il n'y a pas de souci, les pointeurs sont bien là et conservé. Il y a quelque chose qui m'échappe dans tout ça, mais il faudrait m'expliquer quoi...

Je vais essayer d'être plus précis dans l'explication de mon problème et de ce que je veux faire.
J'ai une cinquantaine de fichiers .cc, chacun de ces fichiers contient une fonction. Chaque fonction utilise une liste de mot. Mon but est récupérer et d'organiser ces listes de mots lors de l'exécution du programme. Mais comme je ne passe pas par toutes les fonctions, je suis obligé de mettre les définitions de mes variables en porté globale (en tout cas, je ne vois pas d'autre choix).

Voilà, j'espère que tes lumières m'éclaireront sur ce souci.
0
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
10 févr. 2010 à 11:26
En fait pour moi ta structure qui référence les mots ne devraient pas être un membre statique de la classe mots, mais une instance à part entière (d'un point de vue design, ensuite d'un point de vue technique je vois bien pourquoi tu veux faire une variable statique).

Au niveau de l'incrément je n'avais pas compris que tu avais les deux fichiers ce que tu voulais mettre en évidence. En fait je ne pense pas que ça ait quelque chose à voir avec la stl.

a.hpp

#include <set>

#ifndef A_HPP
#define A_HPP

struct A{
    static int n;
    static std::set<int> s;
    A(int c){
        ++n;
        s.insert(c);
    }
};

int A::n = 0;
std::set<int> A::s = std::set<int>();

inline void g(){
    A a5(5),a6(6);
}

#endif


main.cpp

#include <iostream>
#include "a.hpp"

void f(){
    A a3(3),a4(4);
}

void display_set(){
    std::set<int>::const_iterator
        sit (A::s.begin()),
        send(A::s.end());
    std::cout << '{';
    for(;sit!=send;++sit) std::cout << *sit << ' ';
    std::cout << '}' << std::endl;
}

int main(){
    A a1(1),a2(2);
    std::cout << A::n << std::endl;
    display_set();
    f();
    std::cout << A::n << std::endl;
    display_set();
    g();
    std::cout << A::n << std::endl;
    display_set();
    return 0;
}


donne :

2
{1 2 }
4
{1 2 3 4 }
6
{1 2 3 4 5 6 }


Pour moi c'est toi qui utilises mal tes variables statiques ou le mot clé extern. En C et en C++,
- un symbole (fonction, variable) statique déclaré hors d'une fonction se comporte comme un symbole global au sein du fichier ;
- une variable statique dans une fonction est persistante entre deux appels de cette fonction

En C++ un membre statique (attribut ou méthode) n'est pas rattaché à une instance de classe. L'intérêt des membres statiques est de pouvoir définir une portée (protected, public...) et d'encapsuler ce membre dans une classe et ainsi de mieux architecturer le code.

En espérant que ça t'aide.
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
10 févr. 2010 à 12:29
ça ne m'aide pas car je le sais déjà.
Je pense que tu as mal regardé le code exemple que j'ai fourni : je défini mes variables en dehors de toute fonction, je pense que c'est ça qui pose problème. Mais pourquoi ???

Si tu as le temps essai de compiler et de comprendre mes fichiers.
J'ai bien compris qu'une variable statique revenait à une variable globale (d'ailleurs dans le petit exemple que je donne j'utilise une variable globale) mais le fond du problème c'est que c'est un peu comme si elle se dupliquait entre les deux fichiers.
Un démonstrateur un peu plus propre :
demonstrate.h
#include <vector>
#include <string>
#include <iostream>
extern std::vector<char*> l;
struct A{A(char* A);};

def.cpp
#include "demonstrate.h"
std::vector<char*>l;
struct A
{
  A(char *a){l.push_back(a);std::cout<<a<<" constructeur\n";}
};

main.cc
#include "demonstrate.h"
A a("essai");
A b("essa2i");
int main()
{
     std::cout<<l.size()<<"\n";// devrai rendre 4
     for(int i=0;i<l.size();++i)
          std::cout<<l[i]<<"\n";
     return 0;
}


et un fichier machin.cpp :

#include "demonstrate.h"
A c("dkjf");
A d("flgkfd");
void lisdf()
{ 
       return;
}


Sortie :
dkjf constructeur
flgkfd constructeur
essai constructeur
assa2i constructeur
2
essai
assa2i


0
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
11 févr. 2010 à 02:38
J'ai bien compris ton problème.

Par contre je me suis mal explqiuée dans mon message précédent. Le but de ma réponse était de te montrer :
1) comment utiliser les variables statiques,
2) te montrer que la stl n'a rien à voir avec ton problème.

Je vais te donner un exemple de code qui va à mon avis t'intéresser et qui se rapproche de ce que tu veux faire :

a.hpp

#ifndef A_HPP
#define A_HPP
#include <iostream>

void f();

struct A{
     A(int);
};

#endif


a.cpp

#include "a.hpp"
#include <set>

std::set<int> x;

A::A(int a){
    x.insert(a);
    std::cout << "adding " << a << std::endl;
}

void f(){
    A a3(3);
    A a4(4);
}


main.cpp

#include <set>
#include <iostream>
#include "a.hpp"

extern std::set<int> x;

template <typename T>
std::ostream & operator << (std::ostream & out,const std::set<T> & s){
    typename std::set<T>::const_iterator
        sit (s.begin()),
        send(s.end());
    out << "{ ";
    for(;sit!=send;++sit) out << *sit << ' ';
    out << "}";
    return out;
}

int main(){
    std::cout << "0) " << x << std::endl;
    A a1(1);
    A a2(2);
    std::cout << "1) " << x << std::endl;
    f();
    std::cout << "2) " << x << std::endl;
    return 0;
}


Ce qui donne :

(mando@aldur) (~) $ g++ -c a.cpp
(mando@aldur) (~) $ g++ main.cpp a.o
(mando@aldur) (~) $ ./a.out
0) { }
adding 1
adding 2
1) { 1 2 }
adding 3
adding 4
2) { 1 2 3 4 }


Comme tu le vois le container STL (ici un std::set) n'a pas perdu de valeur et on est bien passé 4 fois dans le constructeur de A. Au niveau de ton code je ne sais pas ce qui cloche, mais un coup tu parles de static, un coup d'extern j'ai un peu de mal à voir.

Si l'on met de côté la question du comportement "2 au lieu de 4" de côté, je pense qu'il suffit simplement que tu utilises un design un peu plus propre comme celui que loupious a proposé (ou que j'ai proposé).

Bonne chance
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
11 févr. 2010 à 08:24
Si l'on met de côté la question du comportement "2 au lieu de 4" de côté,
Oui, mais non, car c'est justement ça qui m'ennuie !
Tu remarquera que dans vos codes toutes les variables que vous utiliser son définies dans le corps d'une fonction. Moi, je les met en porté globale. Ceci n'est peut être pas très propre, mais je ne vois pas d'autre solution.
Pourquoi ? car, en reprenant ton exemple, je voudrais récupérer les valeurs passer à a3 et a4 avant d'appeler f() ou sans appelé f(). Ce n'est pas juste une torture de l'esprit, c'est comme je le disais le but de récupérer des informations disséminées dans une cinquantaine de fichiers, avec des fonctions qui ne sont pas forcément appelées (if(OPT) f();else g();). Il n'est pas souhaitable de rapatrier toutes ces données dans unique fichier/fonction car cela risque de créer des problèmes d'oublie ou de truc dans le genre lors des futurs développements.
C'est pour ça que je ne change pas le "design" de ce que je fais et que je m'entête à essayer de comprendre pourquoi mon démonstrateur ne fait pas ce que j'attends de lui. Pour les solutions alternatives, je pourrais peut être essayer d'illustrer mieux ce que j'ai et que je veux faire ?
0
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
11 févr. 2010 à 11:12
Pourquoi ? car, en reprenant ton exemple, je voudrais récupérer les valeurs passer à a3 et a4 avant d'appeler f() ou sans appelé f().

Dans ce cas la il faut simplement faire un appel au niveau de A à cette fonction. Ou maintenir un membre statique dans A (ce sont les deux solutions que je t'ai proposé) ou appeler une méthode statique de A. Pas besoin d'extern dans ce cas.

Moi, je les met en porté globale. Ceci n'est peut être pas très propre, mais je ne vois pas d'autre solution.

Effectivement c'est sale, et en plus c'est sans doute la cause du problème. C'est d'ailleurs les raisons pour lesquelles je t'incite à changer de design.

C'est pour ça que je ne change pas le "design" de ce que je fais et que je m'entête à essayer de comprendre pourquoi mon démonstrateur ne fait pas ce que j'attends de lui. Pour les solutions alternatives, je pourrais peut être essayer d'illustrer mieux ce que j'ai et que je veux faire ?

En effet, car malgré tes explications je ne vois pas trop pourquoi tu ne fais pas une méthode statique comme loupious et moi te le suggérons depuis le début.
0
loupius Messages postés 697 Date d'inscription dimanche 1 novembre 2009 Statut Membre Dernière intervention 31 décembre 2017 148
11 févr. 2010 à 14:40
J'ai regardé ton post n° 8 et j'ai 2 remarques:
- tu passes de variable 'static' à 'global', il n'est pas facile de te suivre dans tes demandes,
- le code donné n'est pas compilable car la structure 'A' est déclarée 2 fois...
Comme mamiemando, j'ai un peu de mal à te suivre... ;-)
Pour les variables globales, il faut faire attention à l'ordre de déclaration des 'globales'.
Regarde les exemples suivants qui ne diffèrent que par l'ordre de déclaration:
#include <string>
#include <vector>
#include <cstdlib>
#include <iostream>
using namespace std;

class Mots
{
  public:
    static vector<string> liste;
    Mots(string a) { liste.push_back(a); }
};

vector<string> Mots::liste;

Mots A("radio");
Mots B("télé");

void unDePlus(string str) { Mots mot(str); }

int main(int argc, char *argv[])
{
  unDePlus("table");
  unDePlus("chaise");
  unDePlus("fauteuil");
  Mots mot("lampe");
  
  for (unsigned int i=0; i<Mots::liste.size(); i++)
    cout << Mots::liste[i] << endl;
  return EXIT_SUCCESS;
}
Résultat:
radio
télé
table
chaise
fauteuil
lampe
class Mots
{
  public:
    static vector<string> liste;
    Mots(string a) { liste.push_back(a); }
};

Mots A("radio");
Mots B("télé");

vector<string> Mots::liste;

void unDePlus(string str) { Mots mot(str); }

int main(int argc, char *argv[])
{
  unDePlus("table");
  unDePlus("chaise");
  unDePlus("fauteuil");
  Mots mot("lampe");
  
  for (unsigned int i=0; i<Mots::liste.size(); i++)
    cout << Mots::liste[i] << endl;
  return EXIT_SUCCESS;
}
Résultat:
table
chaise
fauteuil
lampe

Bonne réflexion.
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
12 févr. 2010 à 12:16
Pour la compilation, en effet, peut être, je n'ai pas testé, il suffit dans def.cc de mettre A::A(char*) à la place de struct... J'ai écris ça rapidos juste pour vous montré ce que donne un démonstrateur un peu plus propre.
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
12 févr. 2010 à 12:25
je regarde ton code, je n'arrive pas à voir la différence...
De plus, il manque radio et télé dans ton deuxième résultat.
Ce que tu as écris me conviens bien, MAIS si tu rajoutes un fichier .c avec des Mots dedans, est-ce qu'il apparaissent dans le résultat ?? chez moi non.
0
loupius Messages postés 697 Date d'inscription dimanche 1 novembre 2009 Statut Membre Dernière intervention 31 décembre 2017 148 > Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023
12 févr. 2010 à 14:26
La différence est l'ordre de déclaration entre les variables globales; il n'y a pas d'oubli dans le résultat, c'est rigoureusement ce que j'obtiens, mais cela peut peut-être dépendre du compilateur.
Une autre manière propre est d'utiliser aussi une fonction membre statique, par exemple:
mots.h
#include <string>
#include <vector>
using namespace std;

class Mots
{
  public:
    static vector<string> liste;
    static void ajoute(string str) { liste.push_back(str); }
};

fonction.cpp
#include "mots.h"
#include <iostream>

void fonction1(void)
{
  Mots::ajoute("radio");
  Mots::ajoute("télé");
}

void fonction2(void)
{
  Mots::ajoute("lampe");
  Mots::ajoute("fauteuil");
  Mots::ajoute("lampe");
}

void fonction3(void)
{
  for (unsigned int i=0; i<Mots::liste.size(); i++)
    cout << Mots::liste[i] << endl;
}

main.cpp
#include <cstdlib>
#include "mots.h"
using namespace std;

vector<string> Mots::liste;

extern void fonction1(void);
extern void fonction2(void);
extern void fonction3(void);

int main(int argc, char *argv[])
{
  fonction1();
  fonction2();
  fonction3();
  
  return EXIT_SUCCESS;
}

[loupius@p3000]$ g++ -Wall main.cpp fonction.cpp
[loupius@p3000]$ ./a.out 
radio
télé
lampe
fauteuil
lampe
[loupius@p3000]$ 
A toi de choisir ce qui te convient le mieux.
Bonne continuation.
0
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752 > loupius Messages postés 697 Date d'inscription dimanche 1 novembre 2009 Statut Membre Dernière intervention 31 décembre 2017
12 févr. 2010 à 14:29
En même temps c'est un peu ce qu'on lui dit de faire depuis le début :-) Merci de poster en bas du fil de discussion.
0
loupius Messages postés 697 Date d'inscription dimanche 1 novembre 2009 Statut Membre Dernière intervention 31 décembre 2017 148 > mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024
12 févr. 2010 à 14:45
Oui mais ne lui dites pas !
Il va peut-être finir par comprendre ... ;-))
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
11 févr. 2010 à 14:43
static ou global, c'est pareil.
Donc, pour essayer d'être plus clair. Voilà ce que j'ai actuellement (simplifier) :
fichier f.cc
void f()
{
     const char* c={"f_mot1","f_mot2"...};
     // ...
     if(variable==c[i]) 
          // faire un traitement particluier dans ce cas là
}

fichier g.cc :
void g()
{
     const char* c={"g_mot1","g_mot2"...};
     // ...
     if(variable==c[i]) 
          // faire un traitement particluier dans ce cas là
}

fichier main.cc
void f();
void g();
int main()
{
    //... des trucs
    if(condition)
        f();
    else
        g();
    // ... d'autre trucs
    return 0;
}

Et maintenant ce que je voudrais faire, c'est récupérer toutes les chaines de caractères (f_mot1, f_mot2, g_mot1 etc.) afin de les organiser et de les afficher.

Comme je ne peut pas appeler f et g dans le même processus, je ne passe pas dans tout le code et donc les variables c ne seront pas toutes définies. L'idée que j'ai eu c'est de toutes les regrouper en porté globale, comme ça moins de souci. Et ensuite avec mon constructeur je met toute ces variables dans une pile.

Autre contrainte, je voudrais qu'a l'avenir lorsqu'un dévellopeur rajoute une nouvelle fonction h() avec de nouveaux mots (h_mot1, h_mot2 ...) l'ajout à la liste se fasse simplement, presque automatiquement.

Voilà, j'espère avoir été plus clair.
0
mamiemando Messages postés 33093 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 mai 2024 7 752
12 févr. 2010 à 11:55
Justement, je t'ai donné au moins deux manières de le faire... proprement :-)

Dans ton cas les variables chaînes f_mot1... g_mot1 sont des variables locales à f() et g(), donc tu ne pourras pas les récupérer à moins de les copier quelque part (dans un objet instancié dans le main ou dans une variable globale par exemple).

Afin de les enregistrer, au lieu de faire un const char * en dur, il suffit d'enregistrer ces mots via une fonction ou une méthode. Voici pour moi les trois manières de faire ça :
- passer un std::set<std::string> (instancié dans main) et le passer à f() et g().
- pour éviter de passer ce set à toutes tes fonctions on peut imaginer qu'il soit global mais je suis pas fan.
- transformer f() et g() en d'un objet "plop" qui stocke ce std::set. Si "plop" peut être instancié plusieurs fois, on peut garantir l'unicité du std::set avec le mot clé statique.

Au cours de mes messages précédents j'ai donné avec loupious une manière de faire qui montrait cette approche de manière propre (la preuve... ça marche :p). Après, tu peux t'acharner avec tes extern et avec des morceaux de code bancales, mais il ne faut pas être surpris du résultat ^^ En soi je comprends ton problème qui consiste à te dire "mais pourquoi ça ne marche pas". Mon avis, c'est que plutôt que de se perdre dans des questions métaphysiques, il faut simplement coder proprement. Car au final, si j'ai bien compris ton propos, le but est d'avoir un code reprenable et maintenable. Du coup... je crois que tout est dit :-)
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
17 févr. 2010 à 13:03
Je met en résolu. Merci à Mamiemando et loupious pour leur patiences et leurs réponses.
En ce qui concerne ce que je cherchais à faire, les réponses donner sont assez clair, je n'y reviens pas.

En revanche, au sujet de pourquoi ce que j'ai fait ne fonctionne pas, j'ai à peu près compris, et tiens à résumé.
Le problème viens du fait que j'utilise des variables globales dans plusieurs fichiers et que suite à une compilation on n'est pas certain de l'ordre dans lequel ces variables seront appelées, du moins entre objet. Par exemple, si on a un fichier avec les variable a puis b et un autre avec c et d, on sait que b sera construit après a et d après c, mais on ne sais pas si ce sera abcd ou cdab.
Pour tester un peu, j'ai modifier ma variable statique contenue dans ma structure de vector à set comme le préconisait Mamiemando, j'ai alors eu des erreurs de segmentation, preuve que l'on n'avait pas encore construit la variable statique (similaire à une variable globale). Il apparait donc qu'avec un vector on peut utiliser cette variable sans l'avoir réellement construite.
Toujours pour tester, j'ai remplacé le constructeur classique de la variable statique :
std::vector<char*> A::l;
par
std::vector<char*>::iterator i1=A::l.begin(),i2=A::l.end(); // pas d'erreur car A::l est déclaré dans la structure
std::vector<char*> A::l(i1,i2);

Et avec cette modification mon problème disparait ! S'il on teste ceci sur le code donné en #12 par loupious, on obtient à nouveau la liste complète des mots dans le deuxième cas.
0