volátil frente a mutable en C ++

85

Tengo una pregunta sobre la diferencia entre volátil y mutable. Me di cuenta de que los dos significan que podría cambiarse. ¿Qué más? ¿Son la misma cosa? ¿Cual es la diferencia? ¿Dónde son aplicables? ¿Por qué se proponen las dos ideas? ¿Cómo utilizarlos de forma diferente?

Muchas gracias.

Skydoor
fuente

Respuestas:

112

Un mutablecampo se puede cambiar incluso en un objeto al que se accede a través de un constpuntero o referencia, o en un constobjeto, por lo que el compilador sabe que no debe guardarlo en la memoria R / O. Una volatileubicación es aquella que se puede cambiar mediante un código que el compilador no conoce (por ejemplo, algún controlador de nivel de kernel), por lo que el compilador sabe que no debe optimizar, por ejemplo, la asignación de registros de ese valor bajo la suposición no válida de que el valor "no puede tener cambiado "desde que se cargó por última vez en ese registro. El compilador recibe un tipo de información muy diferente para detener tipos muy diferentes de optimizaciones no válidas.

Alex Martelli
fuente
13
volatileLos objetos también pueden ser cambiados por procesos que no involucran a la CPU en absoluto. Por ejemplo, un registro de bytes recibidos en un periférico de comunicaciones puede incrementarse al recibir un byte (y esto puede incluso desencadenar una interrupción). Otro ejemplo es un registro de banderas de interrupciones pendientes en un periférico.
Mike DeSimone
55
Además, volatileno solo significa que el objeto puede cambiar fuera del conocimiento del compilador, también significa que las escrituras en el objeto no pueden ser eliminadas por el compilador incluso si esas escrituras parecen ser inútiles. Por ejemplo: x = 1; x = 0; si xes volátil, el compilador debe emitir ambas operaciones de escritura (que pueden ser significativas a nivel de hardware). Sin embargo, para un objeto no volátil, el compilador podría optar por no molestarse en escribir el 1ya que nunca se usa.
Michael Burr
15
Un objeto se puede marcar tanto constcomo volatile! No puede cambiar el objeto, pero se puede cambiar a sus espaldas.
CTMacUser
2
@Destructor: la situación habitual es para escrituras en un registro de dispositivo de hardware.
Michael Burr
5
@Destructor digamos que está controlando el estado de un LED. Escribir 0 lo apaga, escribir 1 lo enciende. Si necesito hacer parpadear el LED para comunicar algún estado de error, pero el compilador decide optimizar todas las escrituras excepto la última, ya que no se está usando ninguno de los valores, entonces el LED nunca parpadea y el comportamiento que deseo no se realiza .
iheanyi
28

mutable: La palabra clave mutable anula cualquier instrucción const adjunta. Se puede modificar un miembro mutable de un objeto constante.

volatile: La palabra clave volátil es un modificador dependiente de la implementación, que se usa al declarar variables, lo que evita que el compilador optimice esas variables. Volátil debe usarse con variables cuyo valor puede cambiar de formas inesperadas (es decir, a través de una interrupción), lo que podría entrar en conflicto con las optimizaciones que podría realizar el compilador.

Fuente

xian
fuente
dijiste Volatile should be used with variables whose value can change in unexpected waysque deberíamos preferir usarlo al azar?
Asif Mushtaq
@AsifMushtaq no valores. formas. modifica los permisos que tiene el código que escribe. Por lo tanto, puede acceder a la variable a través de una const ptr o const reference. ¿Y si no es tu código el que lo cambia? ¿Algo de lo que el compilador no puede verificar el ptr o el tipo de referencia? Eso es volátil. Y volátil también obliga a la caché a volver a escribir en la memoria principal. Entonces esto se usa MUCHO con código multiproceso. :)
Dan
22

Definitivamente NO son lo mismo. Mutable interactúa con const. Si tiene un puntero constante, normalmente no podría cambiar miembros. Mutable proporciona una excepción a esa regla.

Volátil, por otro lado, no tiene ninguna relación con los cambios realizados por el programa. Significa que la memoria podría cambiar por razones que escapan al control del compilador, por lo que el compilador tiene que leer o escribir la dirección de la memoria cada vez y no puede almacenar en caché el contenido en un registro.

Ben Voigt
fuente
"Volátil, por otro lado, no tiene ninguna relación con los cambios realizados por el programa ..." - hmmm, haga que un miembro sea volátil y vea qué se rompe durante la compilación. Intentar agregar volátiles después del hecho es muy parecido a tratar de agregar const después del hecho ... Doloroso.
jww
@jww: No tiene ninguna relación con las escrituras realizadas por el programa. Puede tomar la dirección de un objeto de tipo T, almacenarlo en a const T*y leerlo. Si crea ese objeto volatile, el almacenamiento de su dirección const T*fallará, aunque nunca intente escribir. volatiley los cambios / modificaciones / escrituras de memoria del código del programa son completamente ortogonales.
Ben Voigt
17

Una forma tosca pero eficaz de pensar en la diferencia es:

  • El compilador sabe cuándo cambia un objeto mutable.
  • El compilador no puede saber cuándo cambia un objeto volátil.
Jonathan Leffler
fuente
1
En ese sentido: volatilebytes_received, mutablereference_count.
Mike DeSimone
11

Una variable marcada mutablepermite modificarla en un método declarado const.

Una variable marcada volatilele dice al compilador que debe leer / escribir la variable cada vez que su código también lo dice (es decir, no puede optimizar los accesos a la variable).

Kyle Lutz
fuente
4

Me gustaría agregar que volatile también es muy útil cuando se trata de aplicaciones de múltiples subprocesos, es decir, tiene su subproceso principal (donde vive main ()) y genera un subproceso de trabajo que seguirá girando mientras una variable "app_running" es verdadera. main () controla si "app_running" es verdadero o falso, por lo que si no agrega el atributo volátil a la declaración de "app_running", si el compilador optimiza el acceso a "app_running" en el código ejecutado por el subproceso secundario, main ( ) podría cambiar "app_running" a falso, pero el subproceso secundario seguirá ejecutándose porque el valor se ha almacenado en caché. He visto el mismo comportamiento al usar gcc en Linux y VisualC ++. Un atributo "volátil" colocado en la declaración "app_running" resolvió el problema. Entonces,

BinCoder
fuente
1
¡No! Este es un malentendido común. C ++ 11 y C11 introdujeron atomics para este propósito stackoverflow.com/questions/8819095/…
KristianR