Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

variable static non const dans une classe

18 réponses
Avatar
paris.s
Bonjour,

J'ai cherche sur le web et n'ai pas trouve de reponse a ce probleme.

J'ai quelque chose sur le modele:

--- toto.h:

class Toto{
//...

private:
static unsigned var;
};

unsigned Toto::var = 18;

--- fin de toto.h


Le probleme est quand j'inclus toto.h dans plusieurs fichiers .cc qui
sont compiles separement et donnent lieu a plusieurs fichiers .o, au
moment du lien, j'ai une erreur:

multiple definition of 'Toto::var'
first defined in...


Ca semble un probleme classique, qui doit avoir une reponse classique.
Peut-etre dois-je creer un fichier .cc juste pour cette variable --
mais ca serait dommage, j'aimerai bien garde le tout sous forme
d'en-tete car tout le reste est soit inline soit template. Si je peux
eviter de faire une bibliotheque juste pour ca, ca m'arrangerait.

J'utilise: g++ (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-42)
Si vous avez une reponse, j'en serai bien content.

Sylvain

10 réponses

1 2
Avatar
Michel Michaud
Dans le message ,
--- toto.h:

class Toto{
//...

private:
static unsigned var;
};

unsigned Toto::var = 18;

--- fin de toto.h


Le probleme est quand j'inclus toto.h dans plusieurs fichiers .cc
qui sont compiles separement et donnent lieu a plusieurs fichiers
.o, au moment du lien, j'ai une erreur:

multiple definition of 'Toto::var'
first defined in...


Ca semble un probleme classique, qui doit avoir une reponse
classique. Peut-etre dois-je creer un fichier .cc juste pour cette
variable --


Si tu tiens à la variable static, oui.

mais ca serait dommage, j'aimerai bien garde le tout
sous forme d'en-tete car tout le reste est soit inline soit
template. Si je peux eviter de faire une bibliotheque juste pour
ca, ca m'arrangerait.


La solution la plus simple serait de faire un singleton, tiens,
je crois même que tu pourrais faire un « singleton membre static
privé » :

class Toto{
//... Il faudra utiliser « Var() » au lieu de « var »
//
// (en fait, si on y tient vraiment on pourrait ajouter du code
// pouvoir utiliser « var » la plupart du temps :
//
//
// Toto()
// : var(Var())
// { ... }
//
// void F()
// {
// var= 10; // Change en fait la variable valeur de Var()
// }
//
// Avec un membre privé : unsigned& var;
// mais ce serait de l'obfuscation plus qu'autre chose :-)

private:
static unsigned& Var()
{
static unsigned valeur= 18;
return valeur;
}
};

Une meilleure compréhension de ce que tu veux faire pourrait
peut-être permettre une solution moins bizarre...

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/

Avatar
Maxim
class Toto{
private:
static unsigned var;
};
unsigned Toto::var = 18;
[...]

Ca semble un probleme classique, qui doit avoir une reponse classique.
Peut-etre dois-je creer un fichier .cc juste pour cette variable --


C'est effectivement la solution classique pour initialiser une variable
de classe.

--
Maxim
"On ne cognoist point le vin aux cercles."
- proverbe françois

Avatar
Fabien LE LEZ
On 21 Dec 2004 18:05:29 -0800, :

multiple definition of 'Toto::var'
first defined in...


Ca semble un probleme classique, qui doit avoir une reponse classique.


Ben oui. Si le compilo râle (à raison) sur la présence d'une "multiple
definition", c'est parce que l'espace mémoire dédié à ta variable
"Toto::var" est présent dans plusieurs modules.

Peut-etre dois-je creer un fichier .cc juste pour cette variable


C'est à peu près ça. Tu peux aussi la mettre dans un .cpp et un seul.

mais ca serait dommage, j'aimerai bien garde


+s +r

le tout sous forme
d'en-tete car tout le reste est soit inline soit template.


C'est bien agéable quand ça marche, mais c'est loin d'être fréquent...
Pour les variables static const (en fait, les constantes), on s'en
sort par une pirouette : un enum, une fonction, etc.
Mais quand il s'agit bien d'une variable, i.e. d'un espace mémoire
dans lequel le programme stocke une information et la modifie, il n'y
a pas vraiment de solution : il faut lui réserver un espace mémoire
dans un module.


--
;-)

Avatar
Fabien LE LEZ
On Tue, 21 Dec 2004 23:26:44 -0500, "Michel Michaud" :

class Toto{
private:
static unsigned& Var()
{
static unsigned valeur= 18;
return valeur;


Pour le coup, je veux bien que tu m'expliques comment ça marche, quand
le header est #inclus dans plusieurs .cpp.
Pour moi, il y a une variable "static unsigned valeur" par module, par
définition de "static".



--
;-)

Avatar
Michel Michaud
Dans le message ,
On Tue, 21 Dec 2004 23:26:44 -0500, "Michel Michaud" :

class Toto{
private:
static unsigned& Var()
{
static unsigned valeur= 18;
return valeur;


Pour le coup, je veux bien que tu m'expliques comment ça marche,
quand le header est #inclus dans plusieurs .cpp.
Pour moi, il y a une variable "static unsigned valeur" par module,
par définition de "static".


Je ne peux te dire comment ça marche, mais il « faut » que ça marche.

Il y avait un problème pour un cas semblable avec certains compilateurs
pendant un certain temps, pour les simples fonctions globales avec des
static, mais les compilateurs modernes s'occupent sans broncher du cas
simple qui semble pourtant encore moins évident :

// Dans un .h utilisé plusieurs fois, il doit y avoir une seule
// variable valeur quand même.
inline int& Valeur() // Remplace avantageusement une variable
{ // globale...
static int valeur= 0;
return valeur;
}

Alors j'imagine que le cas d'une fonction dans la classe devrait
être semblable, non ? En fait, peut-être même que c'est moins
problématique, considérant que les fonctions membres statiques
sont depuis toujours considérées comme des « méthodes de classe »
selon les appellations courantes dans d'autres langages.

Mais il faudrait peut-être vérifier avec quelques « vieux »
compilateurs... et quelques nouveaux ! Ceci dit, ici on parle
ISO C++ alors la question ne se pose pas et c'est pourquoi les
tests sont laissés en exercice :-)

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/


Avatar
kanze
Fabien LE LEZ wrote:
On 21 Dec 2004 18:05:29 -0800, :

multiple definition of 'Toto::var'
first defined in...

Ca semble un probleme classique, qui doit avoir une reponse
classique.



Ben oui. Si le compilo râle (à raison) sur la présence d'une
"multiple

definition", c'est parce que l'espace mémoire dédié à ta variable
"Toto::var" est présent dans plusieurs modules.


Ce qui veut dire quoi, au juste ? Si j'écris dans un en-tête :

template< typename T >
struct X { static int i ; } ;

template< typename T >
int x::i ;

et que j'instancie le template sur le même type dans plusieurs unités
de
compilation, qu'est-ce qui se passe ?

Si le compilateur râle qu'il y a une définition multiple, c'est qu'il
y
a une définition multiple dans un contexte où la norme l'interdit.
(Formellement, c'est un comportement indéfini, je crois, mais tous les
compilateurs que je connais s'en plaignent.)

En fait, dans un compilateur moderne, il y a plusieurs choses que le
compilateur peut dire à l'éditeur de liens au sujet d'un symbole :

-- Ce sont mes oignons. (Il se tait sur le symbole, on ne le met que
dans les informations de deboggage.)

-- Je ne le connais pas -- aide-moi. (Et si la définition n'est pas
fournie par une autre unité de compilation, l'éditeur de liens va
râler : extern non résolu.)

-- C'est ici LA définition. La seule et unique définition : c'est
moi
le boss, et si quelqu'un essaie d'en donner une autre définition,
même identique, l'éditeur de liens râle.

-- C'est ici UNE définition. Mais d'autres unités de compilation
peuvent aussi en fournir. Typiquement, l'éditeur de liens en
choisit
une des définitions, selon ses propres règles, et en jette les
autres à la poubelle, sans râler. (Il serait rélativement facile
à
faire un éditeur de liens qui vérifierait que les autres
définitions
étaient plus ou moins équivalentes, et qui râlerait dans le cas
contraire, mais je n'en connais pas qui le font.)

Note que si on a tendance à associer cette dernière possibilité
aux
templates, il existe en fait depuis longtemps pour des bloc commun
de Fortran... et pour certains compilateurs C pré-norme.

Dans le cas en question, la norme dit que le compilateur a droit de
s'affirmer, et de mettre le symbole dans le troisième cas. (Un
compilateur qui le mettait dans le cas quatre serait conforme, je
crois.)

--
James Kanze GABI Software http://www.gabi-soft.fr
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


Avatar
Stanislas RENAN

On Tue, 21 Dec 2004 23:26:44 -0500, "Michel Michaud" :


class Toto{
private:
static unsigned& Var()
{
static unsigned valeur= 18;
return valeur;



Pour le coup, je veux bien que tu m'expliques comment ça marche, quand
le header est #inclus dans plusieurs .cpp.
Pour moi, il y a une variable "static unsigned valeur" par module, par
définition de "static".


n'y aurait-il pas plusieurs sens à static, selon le contexte dans lequel
il est utilisé ?

-static pour les fonctions/variables statiques de classe ;
-static pour la portée d'une variable globale à l'unité de traduction ;
-static pour la durée de vie d'une variable locale.

ça en fait trois, déjà.
J'ai l'impression que tu confonds les 2 dernières dans l'exemple de
Michel.

--
Stanislas RENAN


Avatar
Fabien LE LEZ
On Wed, 22 Dec 2004 11:27:37 +0100, Stanislas RENAN
:

n'y aurait-il pas plusieurs sens à static, selon le contexte dans lequel
il est utilisé ?


Yep, sans doute nettement plus que les trois que tu cites. Sans
oublier qu'il faut rajouter aussi "inline" là-dedans.

Mais bon, un jour j'arriverai à comprendre tout ça[*].


[*] You may say I'm a dreamer, but I'm not the only one...


--
;-)

Avatar
paris.s
Bonjour,

Ce que je veux faire est assez simple. J'ai du code C qui fait une
transformee de Fourier efficace mais dont la syntaxe est plutot obscure
(http://www.fftw.org/). J'ai encapsulee la partie qui m'interesse dans
une classe C++ avec une syntaxe plus claire (selon mon point de vue, je
le concois). Du coup, la plupart des fonctions sont tres courtes et je
les ai declarees 'inline'. En plus, ca me permet de n'avoir qu'un seul
fichier '.h' a inclure.

Les variables 'static' qui apparaissent son les reglages generaux de la
transformee de Fourier:
- un drapeau pour dire comment choisir la methode de calcul,
- le nom du fichier ou sont enregistrees des infos pour faire ce choix
plus rapidement,
- le nombre d'instances que j'ai en cours pour ne lire le fichier
precedent que la premiere fois et pour enregistrer un nouveau fichier
une fois la derniere instance detruite.

Et mon souhait est toujours d'eviter d'avoir a manipuler une
bibliotheque juste pour trois lignes d'initialisation de variables
'static'.

Merci pour les conseils,

Sylvain
Avatar
paris.s
Bonjour,

Si je comprends, ce que je souhaite est me placer dans le cas (4): ne
garder qu'une seule des definitions vu que ce sont toutes les memes. Y
a-t-il moyen de "suggerer" ce comportement?

Je pourrais mettre un 'template' juste pour la forme mais ce ne me
semble pas tres "esthetique".

Sylvain
1 2