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

signification de mutable et volatile

83 réponses
Avatar
Stephane Wirtel
Bonjour à tous,

Lisant parfois du code avec ces mots réservés, je me demande maintenant
quelles sont les fonctionnalités de ces deux mots.

Une petite explication ou une doc m'expliquant clairement le but de ces
deux mots réservés.

Merci,

Stéphane.

10 réponses

1 2 3 4 5
Avatar
Fabien LE LEZ
On Wed, 22 Dec 2004 19:25:30 +0100, Stephane Wirtel
:

Lisant parfois du code avec ces mots réservés, je me demande maintenant
quelles sont les fonctionnalités de ces deux mots.


mutable : désigne une variable membre qui peut être modifiée par une
fonction const.

Exemple : une classe nombre, avec une fonction membre "racine carrée"
peut s'écrire :

class Nombre
{
public:
double RacineCarree() const { return sqrt (n); }
private:
double n;
};

Supposons maintenant que tu trouves l'appel systématique à la fonction
sqrt() trop lent. Tu peux optimiser le truc en stockant sa valeur :

class Nombre
{
public:
double RacineCarree() const
{
if (le_nombre_a_change)
{
racine_carree= sqrt (n); // !
}
return racine_carree;
}
private:
double n;
double racine_carree;
};

Problème ici : la fonction RacineCarree() ne modifie pas la valeur de
l'objet, donc elle doit être déclarée const. Mais malgré tout, elle
modifie une variable membre (une variable "temporaire" qui ne sert
qu'à éviter de faire plusieurs fois les calculs). On déclare donc
cette variable "mutable" :

class Nombre
{
...
private:
double n;
mutable double racine_carree;
};


--
;-)

Avatar
Stephane Wirtel
Merci pour l'explication de mutable, est-ce que cela est souvent employé
? Il faut dire que dans mon cas personnel, je ne pense pas, mais
peut-être que je l'utiliserai.


Stéphane
Avatar
Fabien LE LEZ
On Wed, 22 Dec 2004 20:17:39 +0100, Stephane Wirtel
:

Merci pour l'explication de mutable, est-ce que cela
est souvent employé ?


Je l'utilise très rarement, et uniquement dans le cas que j'ai cité :
une optimisation consistant à éviter de calculer plusieurs fois la
même chose.


--
;-)

Avatar
Loïc Joly
Stephane Wirtel wrote:

Bonjour à tous,

Lisant parfois du code avec ces mots réservés, je me demande maintenant
quelles sont les fonctionnalités de ces deux mots.


mutable

La constance d'un objet peut être définie de façon bit à bit ou de façon
sémentique. La définition sémentique est souvent celle qu'on veut. En
C++, par défaut, il s'agit de la façon bit à bit, mais on peut lui
indiquer grâce à mutable que certaines données membre ne sont pas à
prendre en compte pour la constance.

Comme Fabien, je ne m'en sert que pour optimiser, et donc uniquement
pour des données membres qui ne font pas partie de l'interface publique
de ma classe (y compris par accesseurs).


volatile

Ce que ça signifie formellement, je n'en sais rien. Et je doute que l'on
puisse trouver deux personnes qui disent savoir et qui soient d'accord
entre elles ;).

En pratique, c'est destiné, par exemple, pour de la mémoire qui
correspond à un mappage d'une carte d'extension, et qui donc peut
changer de contenu sans que le processeur soit au courant. Ca a pour but
de désactiver certaines optimisations qui ne sont plus valables dans ce
contexte. Par exemple a=b; a=b; ne pourra pas être simplifié en un seul
a=b; si b est volatile. A part des gens écrivant des drivers, je ne
pense pas que ce soit vraiment utilisé.

Pour info, il y a des gens qui ont détourné ce mot clef, car comme il
fait partie du système de type, ils l'utilisent pour différentier deux
types de variables. Mais il s'agit d'un hack immonde qui n'a rien à voir
avec le vrai rôle de volatile.

--
Loïc

Avatar
PRORIOL Fabien
Bonsoir,

Je m'en sert aussi pour une autre chose :

imagine que tu veux réaliser une liste (sans utilisé la STL) chainé
encapsuler dans une classe et accessible par 2 methodes :
a.init() qui place "l'iterateur" au debut de la liste.
a.lire() qui retourne l'objet et place l'iterateur sur l'objet suivant

cette classe contiendrait ces attribut

un_pointeur_du_debut_de_la_liste
un_pointeur_iterateur

la methode init() fait donc
un_pointeur_du_debut_de_la_liste=un_pointeur_iterateur;

la methode lire() fait un_pointeur_iterateur un_pointeur_iterateur->suivant();

Tout fonctionne a merveille jusqu'a ce que l'on souhaite être un peu plus
stricte :
init() et lire() ne modifie en rien la structure de donné, il devrait etre
donc déclaré "const". Mais voila, il modifie un membre de la classe, donc
pas possible!!!
Ben pour resoudre ce problème, il suffit de déclarer
mutable un_pointeur_iterateur;

Et tout fonctionne pour le mieu ;-)

@+Fab
Avatar
Christophe Lephay
"PRORIOL Fabien" a écrit dans
le message de news: 41c9f30a$0$4682$
imagine que tu veux réaliser une liste (sans utilisé la STL) chainé
encapsuler dans une classe et accessible par 2 methodes :
a.init() qui place "l'iterateur" au debut de la liste.
a.lire() qui retourne l'objet et place l'iterateur sur l'objet suivant

cette classe contiendrait ces attribut

un_pointeur_du_debut_de_la_liste
un_pointeur_iterateur

la methode init() fait donc
un_pointeur_du_debut_de_la_liste=un_pointeur_iterateur;

la methode lire() fait un_pointeur_iterateur > un_pointeur_iterateur->suivant();

Tout fonctionne a merveille jusqu'a ce que l'on souhaite être un peu plus
stricte :
init() et lire() ne modifie en rien la structure de donné, il devrait etre
donc déclaré "const". Mais voila, il modifie un membre de la classe, donc
pas possible!!!
Ben pour resoudre ce problème, il suffit de déclarer
mutable un_pointeur_iterateur;

Et tout fonctionne pour le mieu ;-)


Dans ce cas précis (rien à voir avec mutable, donc), je pense que ce serait
un meilleur design de faire une classe iterateur (au lieu d'un simple
pointeur) et de faire de lire() et init() des membres de ta classe iterateur
(init() peut très bien être remplacé par le constructeur, le cas échéant).
;)

Chris

Avatar
drkm
Loïc Joly writes:

volatile

Ce que ça signifie formellement, je n'en sais rien. Et je doute que l'on
puisse trouver deux personnes qui disent savoir et qui soient d'accord
entre elles ;).


7.1.5.1/8 :

[Note: volatile is a hint to the implementation to avoid
aggressive optimization involving the object because the value of
the object might be changed by means undetectable by an
implementation.

Évidemment, ça aide pas.

--drkm

Avatar
Jean-Marc Bourguet
"Alain Naigeon" writes:

"drkm" a écrit dans le message news:

Loïc Joly writes:

volatile

Ce que ça signifie formellement, je n'en sais rien. Et je doute que l'on
puisse trouver deux personnes qui disent savoir et qui soient d'accord
entre elles ;).


7.1.5.1/8 :

[Note: volatile is a hint to the implementation to avoid
aggressive optimization involving the object because the value of
the object might be changed by means undetectable by an
implementation.

Évidemment, ça aide pas.


Je prends en route, donc, si ce texte laisse de côté une question
précise que vous auriez évoquée, je me retire sur la pointe des
pieds.
Ceci dit, veux-tu dire que le texte ci-dessus n'est pas clair ? Je le
trouve limpide, pour ma part.


A ma connaissance, le seul effet definit par le langage qu'a volatile
est celui de rendre valide certaines lectures apres un longjmp (et
encore, j'ai pas les normes sous la main et je me demande maintenant
si celle du C++ n'enleve pas une partie de ce que dit celle du C) et
de plus les longjmp en C++...

Pour le reste, c'est tres vague. C'est quoi une optimisation
agressive? Est-ce que deplacer une lecture avant ou une ecriture
apres un acces a une variable volatile en est une? Ca gene
l'utilisation de variables volatile comme synchronisation. Est-ce
qu'acceder a une valeur en cache en est une? Sur certaines
architectures multi-processeurs, il faut synchroniser explicitement
les caches. Ces deux choses ne sont generalement pas traitees par
volatile tel qu'implemente par la plupart des compilateurs (en fait je
n'en connais pas qui les traite).

A mon avis, l'utiliser pour autre chose que
- conserver des valeurs apres un longjmp (et voir ma remarque
ci-dessus)
- acceder a des IO mappees en memoire (et donc avec cache
desactive) ce pour quoi il a ete concu a la base,
c'est chercher des problemes. En particulier toute utilisation dans
du cadre du multithread ne fonctionnera au mieux que sur des
mono-processeurs ou certaines familles de multi-processeurs mais
echouera sur d'autres (l'Alpha et les architecture NUMA en
particulier). A ma connaissance, volatile n'entraine par aucun
compilateur l'utilisation de barrieres memoire, ce qui fait que tout
acces a un cache non synchronise va avoir des effets bizarres.

Quelques references:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1680.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1738.pdf
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

* "John Mashey" et "volatile" sur comp.arch.

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



Avatar
kanze
Loïc Joly wrote:
Stephane Wirtel wrote:

Lisant parfois du code avec ces mots réservés, je me demande
maintenant quelles sont les fonctionnalités de ces deux mots.


mutable

La constance d'un objet peut être définie de façon bit à bit ou
de

façon sémentique. La définition sémentique est souvent celle
qu'on

veut. En C++, par défaut, il s'agit de la façon bit à bit, mais on
peut lui indiquer grâce à mutable que certaines données membre ne
sont

pas à prendre en compte pour la constance.

Comme Fabien, je ne m'en sert que pour optimiser, et donc uniquement
pour des données membres qui ne font pas partie de l'interface
publique de ma classe (y compris par accesseurs).


Un cas classique : j'utilise les pointeurs à comptage de référence
invasif, c-à-d que le compteur des références fait parti. Alors,
pour
supporter des pointeurs à des objets const, le compteur est bien
mutable. Ce qui est logique, parce que le nombre de pointeurs vers
l'objet ne fait pas réelement partie de l'état de l'objet.

volatile

Ce que ça signifie formellement, je n'en sais rien. Et je doute que
l'on puisse trouver deux personnes qui disent savoir et qui soient
d'accord entre elles ;).


La norme l'utilise surtout dans sa définition du comportement
observable -- l'accès à un objet volatile est un comportement
observable. Mais ce qui constitue un accès dans cette contexte est
défini par l'implémentation. Alors, on n'est pas bien avancé.

En général, je dirais que si tu as besoin de poser la question sur sa
signification, tu n'en as pas besoin. Sur des systèmes moderne (Unix,
Windows), il n'a pas d'utilité dans des programmes applicatifs. (Selon
la façon qu'il est traité par le compilateur, il pourrait avoir une
utilité dans des pilotes des périphériques ou dans le noyau du
système.
Pourrait, parce que tel qu'il est traité par Sun CC ou par g++, ce
n'est
pas le cas sous Solaris sur un Sparc.)

Typiquement, c'est dans le processeurs embarqués où il trouve son
utilité.

En pratique, c'est destiné, par exemple, pour de la mémoire qui
correspond à un mappage d'une carte d'extension, et qui donc peut
changer de contenu sans que le processeur soit au courant. Ca a pour
but de désactiver certaines optimisations qui ne sont plus valables
dans ce contexte. Par exemple a=b; a=b; ne pourra pas être
simplifié

en un seul a=b; si b est volatile. A part des gens écrivant des
drivers, je ne pense pas que ce soit vraiment utilisé.

Pour info, il y a des gens qui ont détourné ce mot clef, car comme
il

fait partie du système de type, ils l'utilisent pour différentier
deux

types de variables. Mais il s'agit d'un hack immonde qui n'a rien à
voir avec le vrai rôle de volatile.


J'imagine qu'ils ont pensé que puisque le vrai rôle n'a pas de
signification dans la contexte donnée, le mot était libre:-).

Mais c'est effectivement important à noter qu'au contraire de mutable,
il fait bien partie du système de types.

--
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
kanze
Jean-Marc Bourguet wrote:
"Alain Naigeon" writes:

"drkm" a écrit dans le message news:

Loïc Joly writes:

volatile

Ce que ça signifie formellement, je n'en sais rien. Et je
doute




que l'on puisse trouver deux personnes qui disent savoir et qui
soient d'accord entre elles ;).


7.1.5.1/8 :

[Note: volatile is a hint to the implementation to avoid
aggressive optimization involving the object because the
value



of the object might be changed by means undetectable by an
implementation.

Évidemment, ça aide pas.


Je prends en route, donc, si ce texte laisse de côté une question
précise que vous auriez évoquée, je me retire sur la pointe des
pieds. Ceci dit, veux-tu dire que le texte ci-dessus n'est pas
clair ? Je le trouve limpide, pour ma part.


A ma connaissance, le seul effet definit par le langage qu'a volatile
est celui de rendre valide certaines lectures apres un longjmp (et
encore, j'ai pas les normes sous la main et je me demande maintenant
si celle du C++ n'enleve pas une partie de ce que dit celle du C) et
de plus les longjmp en C++...


Il y a aussi que tu peux écrire un volatile sig_atomic_t dans un
handler de signal.

Il y a surout que les accès à un objet volatile font partie du
comportement visible de ton programme. Bien que là, évidemment, ce
qu'on
entend par « accès » est laissé à l'implémentation -- beaucoup de
compilateurs se contentent à le définir comme l'exécution d'une
instruction de load ou de store, alors que nous savons qu'avec les
pipelines d'un processeur moderne, c'est loin de suffire.

Pour le reste, c'est tres vague. C'est quoi une optimisation
agressive? Est-ce que deplacer une lecture avant ou une ecriture
apres

un acces a une variable volatile en est une? Ca gene l'utilisation de
variables volatile comme synchronisation. Est-ce qu'acceder a une
valeur en cache en est une? Sur certaines architectures
multi-processeurs, il faut synchroniser explicitement les caches. Ces
deux choses ne sont generalement pas traitees par volatile tel
qu'implemente par la plupart des compilateurs (en fait je n'en
connais

pas qui les traite).


La norme est assez clair que l'accès à un objet volatile doit avoir
lieu
avant le point de séquencement suivant.

En ce qui concerne la synchronisation, je crois que c'est assez clair
aussi que le comportement particulier des objets volatile ne concerne
que les objets volatile, c-à-d que le compilateur est libre à
déplacer
les autres accès comme il veut, dans la mésure que ça ne change pas
ce
qu'on écrit à un volatile ou qu'on écrit vers une sortie (FILE* ou
streambuf).

En ce qui concerne les architectures multi-processeur, c'est à mon
avis
assez clair ce que la norme *veut*, c-à-d l'intention. C'est que si
j'écris dans un objet volatile sur un processeur, le résultat de
cette
écriture soit immédiatement visible aux lectures à travers un
volatile
sur un autre processeur (qu'il s'agit des threads, ou de la mémoire
partagée et deux processus). Mais la norme ne l'exige pas, même si
c'est
l'intention, et dans la pratique, les compilateurs Sparc (les seuls que
je connais à cet égard) ne l'implémentent pas. En plus, Posix
fournit
d'autres méthodes de synchronisation, et ne supporte pas non plus
l'utilisation de volatile ici.

A mon avis, l'utiliser pour autre chose que
- conserver des valeurs apres un longjmp (et voir ma remarque
ci-dessus)
- acceder a des IO mappees en memoire (et donc avec cache
desactive) ce pour quoi il a ete concu a la base,
c'est chercher des problemes.


A mon avis, s'en servir dans un contexte qui ne dépend pas de
l'implémentation, c'est de chercher des problèmes. Sur des petits
processeurs embarqués, par exemple, je m'en servirai éventuellement
pour
me synchroniser sur une interruption.

L'important, c'est que tout sauf l'utilisation avec longjmp (mais il ne
doit pas y avoir des longjmp dans un code C++) ou pour savoir si on a
eu
un signal (avec volatile sig_atomic_t) dépend de l'implémentation. Ce
qui n'est pas réelement autant de problème que ça, parce que quand
on
veut faire des choses comme accéder à des IO mappées mémoire, on
est
dans du code qui dépend de toute façon beaucoup de l'implémentation.

En particulier toute utilisation dans du cadre du multithread ne
fonctionnera au mieux que sur des mono-processeurs ou certaines
familles de multi-processeurs mais echouera sur d'autres (l'Alpha et
les architecture NUMA en particulier).


Avec les threads Posix. Probablement avec les threads Windows aussi.
Mais on peut bien imaginer des modèles de thread où son utilisation
aurait un sens.

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




1 2 3 4 5