volatile vs mutable en C ++

85

J'ai une question sur la différence entre volatile et mutable. J'ai remarqué que les deux signifient que cela pourrait être changé. Quoi d'autre? Sont-ils la même chose? Quelle est la différence? Où sont-ils applicables? Pourquoi les deux idées sont-elles proposées? Comment les utiliser différemment?

Merci beaucoup.

skydoor
la source

Réponses:

112

Un mutablechamp peut être modifié même dans un objet accessible via un constpointeur ou une référence, ou dans un constobjet, de sorte que le compilateur sache ne pas le mettre en mémoire R / O. Un volatileemplacement est celui qui peut être modifié par un code que le compilateur ne connaît pas (par exemple, un pilote au niveau du noyau), donc le compilateur sait ne pas optimiser, par exemple, l'affectation de registre de cette valeur sous l'hypothèse invalide que la valeur "ne peut pas avoir changé "depuis son dernier chargement dans ce registre. Des informations très différentes sont données au compilateur pour arrêter des types très différents d'optimisations invalides.

Alex Martelli
la source
13
volatileles objets peuvent également être modifiés par des processus n'impliquant pas du tout la CPU. Par exemple, un registre octets reçus dans un périphérique de communication peut s'incrémenter à la réception d'un octet (et cela peut même déclencher une interruption). Un autre exemple est un registre d'indicateurs d'interruptions en attente dans un périphérique.
Mike DeSimone
55
De plus, volatilecela ne signifie pas seulement que l'objet peut changer en dehors de la connaissance du compilateur - cela signifie également que les écritures sur l'objet ne peuvent pas être éliminées par le compilateur même si ces écritures semblent inutiles. Par exemple: x = 1; x = 0; si xest volatile, le compilateur doit émettre les deux opérations d'écriture (ce qui peut être significatif au niveau matériel). Cependant, pour un objet non volatile, le compilateur pourrait choisir de ne pas se soucier d'écrire le 1car il n'est jamais utilisé.
Michael Burr
15
Un objet peut être marqué à la fois constet volatile! Vous ne pouvez pas changer l'objet, mais il peut être changé derrière votre dos.
CTMacUser
2
@Destructor: la situation habituelle est pour les écritures dans un registre de périphérique matériel.
Michael Burr
5
@Destructor disons que vous contrôlez l'état d'une LED. Ecrire 0 le désactive, écrire 1 le met en marche. Si j'ai besoin de faire clignoter la LED pour communiquer un état d'erreur, mais que le compilateur décide d'optimiser toutes les écritures sauf la dernière, car aucune des valeurs n'est utilisée, alors la LED ne clignote jamais et le comportement que je souhaite n'est pas réalisé .
iheanyi
28

mutable: Le mot-clé mutable remplace toute instruction const englobante. Un membre mutable d'un objet const peut être modifié.

volatile: Le mot clé volatile est un modificateur dépendant de l'implémentation, utilisé lors de la déclaration de variables, qui empêche le compilateur d'optimiser ces variables. Volatile doit être utilisé avec des variables dont la valeur peut changer de manière inattendue (par exemple via une interruption), ce qui pourrait entrer en conflit avec les optimisations que le compilateur pourrait effectuer.

La source

xian
la source
vous avez dit Volatile should be used with variables whose value can change in unexpected waysdevrions-nous préférer l'utiliser avec aléatoire?
Asif Mushtaq
@AsifMushtaq pas des valeurs. façons. mutable affecte les permisions du code que vous écrivez. Vous pouvez donc accéder à la variable via une référence const ptr ou const. Et si ce n'était pas votre code qui le changeait? Quelque chose que le compilateur ne peut pas vérifier le type de ptr ou de référence? C'est volatile. Et volatile force également l'écriture du cache dans la mémoire principale. Donc, c'est beaucoup utilisé avec du code multi-thread. :)
Dan
22

Ce n'est certainement PAS la même chose. Mutable interagit avec const. Si vous avez un pointeur const, vous ne pouvez normalement pas changer de membre. Mutable fournit une exception à cette règle.

Volatile, en revanche, n'a aucun rapport avec les modifications apportées par le programme. Cela signifie que la mémoire peut changer pour des raisons indépendantes de la volonté du compilateur, par conséquent, le compilateur doit lire ou écrire l'adresse mémoire à chaque fois et ne peut pas mettre en cache le contenu dans un registre.

Ben Voigt
la source
"Volatile, d'un autre côté, n'a aucun rapport avec les changements apportés par le programme ..." - hmmm, rendre un membre volatil et voir ce qui se brise pendant la compilation. Essayer d'ajouter des éléments volatils après coup, c'est un peu comme essayer d'ajouter des const après coup ... Douloureux.
jww
@jww: Cela n'a aucun rapport avec les écritures faites par le programme. Vous pouvez prendre l'adresse d'un objet de type T, la stocker dans un const T*et la lire. Si vous créez cet objet volatile, le stockage de son adresse const T*échouera, même si vous n'essayez jamais d'écrire. volatileet les changements / modifications / écritures en mémoire à partir du code du programme sont complètement orthogonaux.
Ben Voigt
17

Une façon brute mais efficace de penser la différence est:

  • Le compilateur sait quand un objet mutable change.
  • Le compilateur ne peut pas savoir quand un objet volatil change.
Jonathan Leffler
la source
1
Dans cette veine: volatilebytes_received, mutablereference_count.
Mike DeSimone
11

Une variable marquée mutablepermet de la modifier dans une méthode déclarée const.

Une variable marquée volatileindique au compilateur qu'il doit lire / écrire la variable à chaque fois que votre code le dit aussi (c'est-à-dire qu'il ne peut pas optimiser les accès à la variable).

Kyle Lutz
la source
4

Je voudrais ajouter que volatile est également très utile lorsqu'il s'agit d'applications multithreading, c'est-à-dire que vous avez votre thread principal (où réside main ()) et que vous créez un thread de travail qui continuera à tourner tant qu'une variable "app_running" est vraie. main () contrôle si "app_running" est vrai ou faux, donc si vous n'ajoutez pas l'attribut volatile à la déclaration de "app_running", si le compilateur optimise l'accès à "app_running" dans le code exécuté par le thread secondaire, main ( ) peut changer "app_running" en false mais le thread secondaire continuera à s'exécuter car la valeur a été mise en cache. J'ai vu le même comportement en utilisant gcc sur Linux et VisualC ++. Un attribut "volatile" placé dans la déclaration "app_running" a résolu le problème. Donc,

BinCoder
la source
1
Non! C'est un malentendu courant. C ++ 11 et C11 ont introduit les atomiques à cet effet stackoverflow.com/questions/8819095/…
KristianR