Variable non nommée

Le
AG
Bonjour,

Je suis sur un code dans lequel il y a la déclaration suivante, dans
le main :

int a=2;

A A(a);

ou A est une class contenant que des membres statiques:

class A
{
static int a1;
public:
A();
A(int);
static int geta(void);
}


J'ai un peu de mal avec cette "déclaration". En essayant de
comprendre, il s'agit d'une variable non nommée ? Ai-je bon ?

l'acces au membre a1 se fait par A::geta(). J'ai besoin de pouvoir
enregistrer la class dans un fichier. j'ai donc défini :

friend ostream & operator<<(ostream & o, A& m);

mais la variable crée par "A A(a);" n'est pas utilisable par ma
fonction. Pourriez vous m'expliquer pourquoi et dans quels cas on
utilise de telle variable "non nommée" ?

Merci d'avance,

Alexandre.
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Fabien LE LEZ
Le #306688
On Wed, 9 May 2007 18:57:39 +0200, "AG"
Je suis sur un code dans lequel il y a la déclaration suivante, dans
le main :

int a=2;

A A(a);


Pour le coup, j'ai moi aussi du mal à comprendre.
J'imagine qu'il s'agit d'une variable qui a le même nom qu'une classe,
et que par miracle, il n'y a pas collusion.

En essayant de
comprendre, il s'agit d'une variable non nommée ?


À ma connaissance, ça n'existe pas en C++.

class A
{
static int a1;
public:
A();
A(int);
static int geta(void);


Peux-tu nous donner le code du constructeur ?
Je m'attends au pire -- par exemple, une initialisation de la variable
membre static avec l'argument du constructeur.
Ce qui voudrait dire que le constructeur est bidon, ou plutôt mal
nommé, et qu'il faudrait écrire :

class A
{
public:
static void SetA (int nouvelle_valeur) { a1= nouvelle_valeur; }
static int GetA() { return a1; }
private:
static int a1;
};


int main()
{
int a=2;
A::SetA (a);
}

M'enfin bon, tout ça a l'air d'un beau bordel.

Sylvain
Le #306687
Fabien LE LEZ wrote on 09/05/2007 19:20:

M'enfin bon, tout ça a l'air d'un beau bordel.


ah ça !... ;)

Sylvain.

James Kanze
Le #306686
On May 9, 7:20 pm, Fabien LE LEZ
On Wed, 9 May 2007 18:57:39 +0200, "AG"
Je suis sur un code dans lequel il y a la déclaration suivante, dans
le main :

int a=2;

A A(a);


Pour le coup, j'ai moi aussi du mal à comprendre.
J'imagine qu'il s'agit d'une variable qui a le même nom qu'une classe,
et que par miracle, il n'y a pas collusion.


Il n'y a pas de miracle. La portée de la variable ne commence
qu'à la fin du « declarator », c-à-d ici qu'au parenthèse
ouvrant. Jusque là, le A en dehors de la fonction reste
visible. Voir §3.3.1 : il y a même un exemple du même genre.

Toujours est-il que c'est le genre de chose à éviter, au moins
que tu vises l'obfuscation.

En essayant de
comprendre, il s'agit d'une variable non nommée ?


À ma connaissance, ça n'existe pas en C++.


Ça s'appelle un temporaire (ou un rvalue). Mais on n'a pas
l'habitude de les considérer comme des variables.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Michael DOUBEZ
Le #306685
Bonjour,

[beau bordel]

l'acces au membre a1 se fait par A::geta(). J'ai besoin de pouvoir
enregistrer la class dans un fichier. j'ai donc défini :

friend ostream & operator<<(ostream & o, A& m);

mais la variable crée par "A A(a);" n'est pas utilisable par ma
fonction. Pourriez vous m'expliquer pourquoi et dans quels cas on
utilise de telle variable "non nommée" ?


As tu essayé de rendre le paramètre const:
friend ostream & operator<<(ostream & o, const A& m);

Ca permet de prendre des variable temporaire en paramètre. (Je n'ai pas
retrouvé la référence dans le standard - j'ai pas beaucoup cherché non
plus.)

Exemple:
#include <iostream>

using namespace std;

//la class A
class A
{
int a1;

public:
A(int a=0):a1(a){}

int geta()const{return this->a1;}

friend ostream & operator<<(ostream & o, const A& m);
};

// l'operateur de streaming
// si on enlève const, ça ne compile plus
ostream & operator<<(ostream & o, const A& m)
{
o<<m.geta();
return o;
}

int main()
{
A a(1);
//la ligne suivante ne compile plus si non-const
cout<<"Named "<<a<<" Unnamed "<<A(2)<<endl;

return 0;
}

Michael

AG
Le #306684
je vous dévoile une partie du code :

class MTRand;
class RandomNumGenerator
{
static MTRand* ptMersenneTwister;
static int StartSeed;
public:
RandomNumGenerator();
RandomNumGenerator(int seed);
~RandomNumGenerator();
static void Init();
static void Init(int seed);
static double rand();
...
};

avec

RandomNumGenerator::RandomNumGenerator(int seed)
{
if (seed == 0)
Init(); // use random without seed if the argument is zero
else
Init(seed); // otherwise use a seed
}

void RandomNumGenerator::Init(int seed)
{
cout << "RandomNumGenerator::Init(int seed)" << endl;
if(ptMersenneTwister)
delete ptMersenneTwister;
if (seed != 0)
ptMersenneTwister = new MTRand(seed);
else
ptMersenneTwister = new MTRand();
}

et dans le main :

int seed = 1234;

RandomNumGenerator RandomNumGenerator(seed);

et de temps en temps des :

RandomNumGenerator::rand() pour avoir un nombre tiré aléatoirement.

Bien sur le programme plante de temps en temps, personne ne sait
pourquoi. J'ai besoin de savoir si ce genre de pratique (qui est
utilisé largement dans le code avec d'autres class) peut causer des
problemes. Merci de me soutenir et de pas me renvoyer dans mes
pennates en me disant simplement qu'on écrit pas du code comme ça :-)

AG.
Jean-Marc Bourguet
Le #306683
James Kanze
Ça s'appelle un temporaire (ou un rvalue). Mais on n'a pas
l'habitude de les considérer comme des variables.


La definition de variable etant pour moi "un objet nomme", une "variable non
nommee" serait donc pour moi un oxymore si la contradiction etait
volontaire.

Outre les temporaires, les objets alloues dynamiquement et les elements des
tableaux ne sont pas nommes.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Laurent Deniau
Le #306681
James Kanze wrote:
On May 9, 7:20 pm, Fabien LE LEZ
On Wed, 9 May 2007 18:57:39 +0200, "AG"
Je suis sur un code dans lequel il y a la déclaration suivante, dans
le main :

int a=2;

A A(a);
Pour le coup, j'ai moi aussi du mal à comprendre.

J'imagine qu'il s'agit d'une variable qui a le même nom qu'une classe,
et que par miracle, il n'y a pas collusion.


Il n'y a pas de miracle. La portée de la variable ne commence
qu'à la fin du « declarator », c-à-d ici qu'au parenthèse
ouvrant. Jusque là, le A en dehors de la fonction reste
visible. Voir §3.3.1 : il y a même un exemple du même genre.

Toujours est-il que c'est le genre de chose à éviter, au moins
que tu vises l'obfuscation.

En essayant de
comprendre, il s'agit d'une variable non nommée ?


À ma connaissance, ça n'existe pas en C++.


Ça s'appelle un temporaire (ou un rvalue). Mais on n'a pas
l'habitude de les considérer comme des variables.


Il y a aussi les parametres des fonctions (que l'on peut assimiler a des
variables) qui peuvent ne pas etre nomme:

void func(int a, int)
{
// ..
}

a+, ld.



Michael DOUBEZ
Le #306680
je vous dévoile une partie du code :

class MTRand;
class RandomNumGenerator
{
static MTRand* ptMersenneTwister;
static int StartSeed;
public:
RandomNumGenerator();
RandomNumGenerator(int seed);
~RandomNumGenerator();
static void Init();
static void Init(int seed);
static double rand();
...
};

avec

RandomNumGenerator::RandomNumGenerator(int seed)
{
if (seed == 0)
Init(); // use random without seed if the argument is zero
else
Init(seed); // otherwise use a seed
}

void RandomNumGenerator::Init(int seed)
{
cout << "RandomNumGenerator::Init(int seed)" << endl;
if(ptMersenneTwister)


Dans ce cas, initialise ptMersenneTwister à NULL.
static MTRand* ptMersenneTwister=NULL;


delete ptMersenneTwister;
if (seed != 0)
ptMersenneTwister = new MTRand(seed);
else
ptMersenneTwister = new MTRand();
}

et dans le main :

int seed = 1234;

RandomNumGenerator RandomNumGenerator(seed);
Eviter la confusion nom/'nom de classe'.



Attention à l'ordre d'initialisation des statiques. Ici, tu en a
plusieurs qui sont concurrentes:
seed
RandomNumGenerator
RandomNumGenerator::ptMersenneTwister
RandomNumGenerator::StartSeed

Tu peux transformer
const int seed = 1234;//en zone RO du code

Tu n'as pas d'intérêt à utiliser des fonctions et variable statiques de
class. Soit:
1 tu mets dans un namespace avec des systèmes de
singleton/initialisation
2 tu définis une class de nombe aléatoire et tu la rends statique

Ici tu fais un mix des deux.
La solution 2 serait:

class MTRand;
class RandomNumGenerator
{
MTRand* ptMersenneTwister;
static int StartSeed;
public:
RandomNumGenerator(int seed=0);
~RandomNumGenerator();
void Init(int seed);
double rand();
...
};

Si rand n'est pas utilisé dans d'autres initialisations statiques:
static const int seed = 1234;
RandomNumGenerator single(seed);

mais si c'est la cas, utiiser le singleton :

RandomNumGenerator& RandNumGene()
{
static const int seed = 1234;
static RandomNumGenerator single(seed);

return single;
}

Puis tu utilise:
RandNumGene().rand();



et de temps en temps des :

RandomNumGenerator::rand() pour avoir un nombre tiré aléatoirement.

Bien sur le programme plante de temps en temps, personne ne sait
pourquoi. J'ai besoin de savoir si ce genre de pratique (qui est
utilisé largement dans le code avec d'autres class) peut causer des
problemes. Merci de me soutenir et de pas me renvoyer dans mes
pennates en me disant simplement qu'on écrit pas du code comme ça :-)


Sylvain
Le #306642
AG wrote on 10/05/2007 09:29:
je vous dévoile une partie du code :

class MTRand;
class RandomNumGenerator
{
static MTRand* ptMersenneTwister;


cette instance (le fournisseur concret de random) n'a aucune raison
d'être static, une variable d'instance privée serait plus adéquate.

static int StartSeed;


il ne semble y voir aucun intérêt à stocker la graine initiale - cela
pourrait être utile uniquement s'il existait une méthode "reset" ou si
la méthode Init sans paramètre utilisait cette graine (la dernière
graine transmisse) or elle utilise zéro par défaut.

public:
RandomNumGenerator();
RandomNumGenerator(int seed);


vu le code, la définition "RandomNumGenerator(int seed = 0);" aurait été
préférable.

~RandomNumGenerator();
static void Init();
static void Init(int seed);


vu le code, la définition "Init(int seed = 0);" aurait été préférable.
les méthodes devraient être non statiques.

static double rand();


la méthode n'a pas d'intérêt à être statique.

le défaut majeur d'avoir ces méthodes statiques et un fournisseur
MTRand* static est évidemment qu'une modification / un appel quelconque
impacte globalement le fournisseur d'aléa; on préférera sûrement pouvoir
disposer de plusieurs instances indépendantes.

en utilisant une (quasi) facade avec un provider interne, on pourrait
préférer:

// déclaration publique

class Randomizer {
private:
Randomizer(const Randomizer&);
protected:
Randomizer() {}
public:
~Randomizer() {}

virtual void init(long seed) {} /* no default initialisation */
virtual void reset() {} /* reset to initial state */

// to be provided by actual implementation
virtual double rand() = 0;
};

class RandomGenerator {
private:
Randomizer* randomizer;
long defaultSeed;
public:
RandomGenerator(long algo, long seed = 0L);
~RandomGenerator();

bool init(long algo, long seed);
void reset();
double rand();
};

// declaration privée et implémentation

// Pseudo-random generator as per MT19937 (Mersenne Twister)

class MTRandom : public Randomizer {
private:
// internal state
// ...

public:
MTRandom();
~MTRandom();

void init(long seed);
void reset();
double rand();
};

// public facade

RandomGenerator::RandomGenerator(long algo, long seed)
{
randomizer = 0;
init(algo, seed);
}

RandomGenerator::~RandomGenerator()
{
if (randomizer)
delete randomizer;
}

bool RandomGenerator::init(long algo, long seed)
{
if (randomizer)
delete randomizer, randomizer = 0;

switch (algo){
case 'MT ':
randomizer = new MTRandom();
break;
// case 'FIPS':
// randomizer = new FipsRandom();
// break;
}
if (randomizer){
randomizer->init(defaultSeed = seed);
return true;
}
return false;
}

void RandomGenerator::reset()
{
if (randomizer)
randomizer->reset();
}

double RandomGenerator::rand()
{
return (randomizer) ? randomizer->rand() : 0.0;
}

et dans le main :


RandomGenerator generator('MT ', 1234);

double d = generator.rand();

Sylvain.

Michael DOUBEZ
Le #306641
AG wrote on 10/05/2007 09:29:
je vous dévoile une partie du code :

[code]


le défaut majeur d'avoir ces méthodes statiques et un fournisseur
MTRand* static est évidemment qu'une modification / un appel quelconque
impacte globalement le fournisseur d'aléa; on préférera sûrement pouvoir
disposer de plusieurs instances indépendantes.


C'est pas sûr, plus on utilise un générateur de nombres aléatoire entre
plusieurs modules, plus les nombres sont décorrélés (pour un module, ça
correspond à un sampling de la sortie du générateur). Un des meilleur
système que j'ai utilisé était un processus en arrière plan qui générait
des nombre continuellement et de lui en demander un quand on en avait
besoin.

Un des intérêts d'avoir une classe de nombre aléatoire est
éventuellement d'en utiliser plusieurs instances initialisés à des seeds
différents pour généré des nombres en les combinant. Ca augmente la
cyclicité du générateur global tout en diminuant la prédictibilité.

Un autre est de fournir la reproductibilité des résultats en cas
d'utilisation multithread en utilisant une instance par thread.

Michael


Publicité
Poster une réponse
Anonyme