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

Initialisation de donnée membre static

14 réponses
Avatar
MGN
Bonjour,
j'ai une classe avec une présentation classique :
- déclarations dans le fichier hpp
- définitions dans le fichier cpp

je me pose la question de la différence entre une variable globale définie
comme suit :
dans cpp :
vector<std::string> x;
et la même chose en tant que membre static private d'une classe
(c'est juste une variable utilisée fréquemment dans certaines méthodes (je
programme un interpréteur))

Dans les deux cas, je ne sais pas comment l'initialiser, excepté dans le
corps du constructeur de la classe qui peut tester si la liste est vide...
Mais je trouve cette solution pas très élégante.
Je veux l'initialiser avec une liste de mots.

est-ce que je peux écrire simplement dans le fichier cpp.
vector<std::string> x;
x.push_back("mot1");
x.push_back("mot2");
etc...

Dans ce cas, quand ce bout de code est exécuté ? (je me pose cette question
parce que ça marche avec mon compilateur, mais que ça me paraît dangeureux
!)

Merci pour vos conseils
Marc

10 réponses

1 2
Avatar
Sylvain Togni
MGN wrote:, :

je me pose la question de la différence entre une variable globale définie
comme suit :
dans cpp :
vector<std::string> x;
et la même chose en tant que membre static private d'une classe
(c'est juste une variable utilisée fréquemment dans certaines méthodes (je
programme un interpréteur))

Dans les deux cas, je ne sais pas comment l'initialiser, excepté dans le
corps du constructeur de la classe qui peut tester si la liste est vide...
Mais je trouve cette solution pas très élégante.
Je veux l'initialiser avec une liste de mots.

est-ce que je peux écrire simplement dans le fichier cpp.
vector<std::string> x;
x.push_back("mot1");
x.push_back("mot2");
etc...


Ce n'est pas légal, c'est sûrement une extension du compilateur.

Personnellement, j'utiliserais une fonction statique (modèle
singleton simplifié) :

staitc std::vector<std::string>&
getX()
{
std::vector<std::string> theX;
theX.push_back("mot1);
theX.push_back("mot2);
return theX;
}

Ce qui règle le problème de l'ordre d'initialisation, mais pas
l'éventuel problème de l'ordre de destruction.

--
Sylvain Togni

Avatar
Sylvain Togni
Sylvain Togni wrote:, :

Personnellement, j'utiliserais une fonction statique (modèle
singleton simplifié) :

staitc std::vector<std::string>&
getX()
{
std::vector<std::string> theX;


J'ai oublié un "static" ici :
static std::vector<std::string> theX;

theX.push_back("mot1);
theX.push_back("mot2);
return theX;
}


--
Sylvain Togni

Avatar
Michel Decima
Sylvain Togni wrote:, :

Personnellement, j'utiliserais une fonction statique (modèle
singleton simplifié) :

staitc std::vector<std::string>&
getX()
{
std::vector<std::string> theX;


J'ai oublié un "static" ici :
static std::vector<std::string> theX;

theX.push_back("mot1);
theX.push_back("mot2);
return theX;
}



Mais maintenant, il y aurat remplissage (ajout) du tableau a chaque
appel de getX, ca va vite devenir un probleme. Il faudrait au moins
ceci pour un comportement correct:

static std::vector<std::string>&
getX()
{
static std::vector<std::string> theX;
static bool initialized = false;

if (!initialized) {
theX.push_back("mot1);
theX.push_back("mot2);
}
return theX;
}


Avatar
Sylvain Togni
Michel Decima wrote:

Personnellement, j'utiliserais une fonction statique (modèle
singleton simplifié) :

staitc std::vector<std::string>&
getX()
{
std::vector<std::string> theX;


J'ai oublié un "static" ici :
static std::vector<std::string> theX;

theX.push_back("mot1);
theX.push_back("mot2);
return theX;
}



Mais maintenant, il y aurat remplissage (ajout) du tableau a chaque
appel de getX, ca va vite devenir un probleme.


C'est vrai

Il faudrait au moins
ceci pour un comportement correct:

static std::vector<std::string>&
getX()
{
static std::vector<std::string> theX;
static bool initialized = false;

if (!initialized) {
theX.push_back("mot1);
theX.push_back("mot2);
}
return theX;
}


Une autre solution serait de construire l'objet d'un coup :

static std::vector<std::string>&
getX()
{
static std::string const tab[] = {
"mot1",
"mot2"
};
static std::vector<std::string> theX(
tab, tab + sizeof(tab)/sizeof(*tab));
return theX;
}

--
Sylvain Togni



Avatar
kanze
MGN wrote:

j'ai une classe avec une présentation classique :
- déclarations dans le fichier hpp
- définitions dans le fichier cpp

je me pose la question de la différence entre une variable
globale définie comme suit :
dans cpp :
vector<std::string> x;


C'est une définition de la variable (avec initialisation par le
constructeur par défaut).

et la même chose en tant que membre static private d'une
classe (c'est juste une variable utilisée fréquemment dans
certaines méthodes (je programme un interpréteur))


C'est à peu près pareil. Quand il s'agit des membres statiques,
ce qu'il y a dans la classe, c'est une declaration, non une
définition. Il faut donc une définition quelque part ailleurs
(dans un cpp).

Dans les deux cas, je ne sais pas comment l'initialiser,


Comme avec n'importe quelle définition.

Donc :

class C
{
public:
static double const f ;
} ;

et dans un cpp :

double C::f = 3.14159 ;

excepté dans le corps du constructeur de la classe qui peut
tester si la liste est vide... Mais je trouve cette solution
pas très élégante. Je veux l'initialiser avec une liste de
mots.

est-ce que je peux écrire simplement dans le fichier cpp.
vector<std::string> x;
x.push_back("mot1");
x.push_back("mot2");
etc...


Non. En revanche, tu peux bien écrire :

static char const* init[] = { "mot1", "mot2" } ;
std::vector< std::string > x( begin( init ), end( init ) ) ;

(Avec les fonctions templatées habituelles :

template< typename T, size_t N >
inline T*
begin( T (&array)[ N ] )
{
return array ;
}

template< typename T, size_t N >
inline T*
end( T (&array)[ N ] )
{
return array + N ;
}

.)

Pareil, évidemment, si l'objet est un membre statique (sauf
qu'il se nomme alors C::x, et non simplement x).

Sinon, tu peux aussi écrire :

static void initX() ;
std::vector< std::string > x ;
static bool dummy = (initX(), true) ;

void initX()
{
x.push_back( "mot1" ) ;
x.push_back( "mot2" ) ;
}

C'est une technique utile quand l'initialisation comporte des
choses qu'on ne peut pas faire avec un constructeur existant.

Dans les deux cas, attention quand même à l'ordre de
l'initialisation, qui n'est pas défini entre des unités de
compilation différente. Si tu t'attends à te servir de cet x
dans le constructeur d'un autre objet statique, dans une autre
unité de compilation, tu risques d'avoir des surprises
désagréables. Dans ces cas-là (et même plus généralement, pour
ne pas exclure cette éventualité à l'avenir), c'est habituel de
se rabattre sur le modèle singleton.

Dans ce cas, quand ce bout de code est exécuté ? (je me pose
cette question parce que ça marche avec mon compilateur, mais
que ça me paraît dangeureux !)


Tel que tu l'as écrit, ça ne doit pas marcher. Tu ne peux mettre
des instructions « exécutables » que dans une fonction. Sauf
qu'évidemment, l'initialisation d'une variable statique peut
comporter des instructions exécutable, par exemple, un
constructeur, ou une expression d'initialisation qui n'est pas
constante. Pour ces instructions-là, la règle veut qu'à
l'intérieur d'une unité de compilation, l'ordre d'initialisation
suit l'ordre des declarations, et que (dans la pratique, au
moins, et dans l'absence d'une édition de liens dynamique)
toutes les initialisations aient lieu avant d'entrer dans
main().

--
James Kanze GABI Software
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
Dominique Vaufreydaz
Bonjour,

Perso, je ferais :
- un membre static
- un autre membre static boolean qui dit si c'est initialise
ou pas (a faux donc dans sa declaration).

dans le h.

class MaClasse:
{
public:
MaClasse();

private: // a voir, ca depend des cas
Chose MonTrucAInitialiser;
bool MonTrucAInitialiserEstIntitialise;
}

dans le cpp :

Chose MaClasse::MonTrucAInitialiser;
bool MaClasse::MonTrucAInitialiserEstIntitialise = false;

Dans le constrcteur de cette class, verifier le booleen et agir
en consequence.

MaClasse::MaClasse()
{
if ( MonTrucAInitialiserEstIntitialise == false )
{
MonTrucAInitialiserEstIntitialise = true;
MonTrucAInitialiser.Init();
}
}

Maitnenant, si il faut aussi detruire proprementl'objet, *dans
certains cas*, il peut etre utilise de rempalcer le booleen par
un compteur d'instance. Quand il est a 1, on initialise quand
il est a 0, on detruit. Ensuite, si on veux initialiser automatiquement
*avant* le main et etre sur que se soit detruit *après* le main,
il suffit de rajouter une instance de la classe en global.

Bien penser au mutex pour proteger l'acces au booleen et
au compteur d'instances, (ca n'est pas dans mon exemple).

En esperant avoir ete clair. Doms.
Avatar
Michel Decima

Pareil, évidemment, si l'objet est un membre statique (sauf
qu'il se nomme alors C::x, et non simplement x).

Sinon, tu peux aussi écrire :

static void initX() ;
std::vector< std::string > x ;
static bool dummy = (initX(), true) ;

void initX()
{
x.push_back( "mot1" ) ;
x.push_back( "mot2" ) ;
}


Il y a une raison particuliere qui justifie l'operateur , dans
l'initialisation de dummy, plutot qu'un initX() qui retourne un bool ?

Avatar
MGN
Merci pour vos réponses
Je m'aperçois que c'est un peu pareil si je fais
if (!theX.empty())
{
theX.push_back("mot1");
theX.push_back("mot2");
}
dans l'appel du constructeur de mes objets mais alors j'ai un test if à
chaque fois...
J'avoue que je ne connaissais pas la syntaxe pour initialiser un vecteur à
partir d'un tableau.
J'ai pourtant plusieurs livres qui parlent de la stl mais ils sont tous très
indigestes :-)
Marc
Avatar
MGN
oui, c'est clair...
je vais faire un truc dans le genre. Pour le cas qui me tracasse, c'est
largement suffisant...
Marc
Avatar
MGN
Sinon, tu peux aussi écrire :

static void initX() ;
std::vector< std::string > x ;
static bool dummy = (initX(), true) ;

Tu n'as pas oublié static devant
std::vector< std::string > x ;
?
Ou tu utilises une variable globale.
Désolé, je comprends pas tout...
En tout cas, merci pour ton effort à me répondre !
Marc
1 2