volatile vs mutabile in C ++


85

Ho una domanda sulla differenza tra volatile e mutevole. Ho notato che entrambi i due significano che potrebbe essere cambiato. Cos'altro? Sono la stessa cosa? Qual è la differenza? Dove sono applicabili? Perché le due idee vengono proposte? Come usarli in modo diverso?

Molte grazie.

Risposte:


112

Un mutablecampo può essere modificato anche in un oggetto a cui si accede tramite un constpuntatore o un riferimento, o in un constoggetto, così il compilatore sa di non metterlo nella memoria R / O. Una volatileposizioneèuna posizione che può essere modificata da un codice di cui il compilatore non è a conoscenza (ad esempio alcuni driver a livello di kernel), quindi il compilatore sa di non ottimizzare, ad esempio l'assegnazione del registro di quel valore sotto il presupposto non valido che il valore "non possa avere cambiato "dall'ultima volta che è stato caricato in quel registro. Tipi molto diversi di informazioni fornite al compilatore per bloccare tipi molto diversi di ottimizzazioni non valide.


13
volatilegli oggetti possono anche essere modificati da processi che non coinvolgono affatto la CPU. Ad esempio, un registro ricevuto dai byte in una periferica di comunicazione può incrementarsi alla ricezione di un byte (e questo può anche attivare un interrupt). Un altro esempio è un registro dei flag di interruzione in sospeso in una periferica.
Mike DeSimone

55
Inoltre, volatilenon significa solo che l'oggetto può cambiare al di fuori della conoscenza del compilatore, ma significa anche che le scritture sull'oggetto non possono essere eliminate dal compilatore anche se quelle scritture sembrano essere inutili. Ad esempio: x = 1; x = 0; se xè volatile, il compilatore deve emettere entrambe le operazioni di scrittura (che potrebbero essere significative a livello hardware). Tuttavia, per un oggetto non volatile, il compilatore potrebbe scegliere di non preoccuparsi di scrivere 1poiché non viene mai utilizzato.
Michael Burr

15
Un oggetto può essere contrassegnato sia conste volatile! Non puoi cambiare l'oggetto, ma puoi cambiarlo alle tue spalle.
CTMacUser

2
@Destructor: la situazione normale è per le scritture su un registro del dispositivo hardware.
Michael Burr

5
@Destructor diciamo che stai controllando lo stato di un LED. Scrivi 0 lo disattiva, scrivi 1 lo attiva. Se devo far lampeggiare il LED per comunicare qualche stato di errore, ma il compilatore decide di ottimizzare tutte le scritture tranne l'ultima, poiché nessuno dei valori viene utilizzato, allora il LED non lampeggia mai e il comportamento che desidero non viene realizzato .
iheanyi

28

mutable: La parola chiave mutable sovrascrive qualsiasi istruzione const racchiusa. Un membro mutabile di un oggetto const può essere modificato.

volatile: La parola chiave volatile è un modificatore dipendente dall'implementazione, utilizzato quando si dichiarano le variabili, che impedisce al compilatore di ottimizzarle. Volatile dovrebbe essere usato con variabili il cui valore può cambiare in modi inaspettati (cioè attraverso un interrupt), che potrebbero entrare in conflitto con le ottimizzazioni che il compilatore potrebbe eseguire.

fonte


hai detto Volatile should be used with variables whose value can change in unexpected waysdovremmo preferirlo usarlo con random?
Asif Mushtaq

@AsifMushtaq non valori. modi. effetti mutabili sulle autorizzazioni del codice che scrivi. Quindi puoi accedere alla variabile tramite un const ptr o un riferimento const. E se non fosse il tuo codice a cambiarlo? Qualcosa di cui il compilatore non può controllare il tipo di riferimento o ptr? Quello è volatile. Inoltre, volatile forza la cache a riscrivere nella memoria principale. Quindi questo è usato molto con codice multi thread. :)
Dan

22

Non sono decisamente la stessa cosa. Mutable interagisce con const. Se si dispone di un puntatore const, normalmente non è possibile modificare i membri. Mutable fornisce un'eccezione a quella regola.

Volatile, d'altra parte, è totalmente estraneo alle modifiche apportate dal programma. Significa che la memoria potrebbe cambiare per motivi che sfuggono al controllo del compilatore, quindi il compilatore deve leggere o scrivere l'indirizzo di memoria ogni volta e non può memorizzare nella cache il contenuto in un registro.


"Volatile, d'altra parte, è totalmente estraneo alle modifiche apportate dal programma ..." - hmmm, rendi un membro volatile e guarda cosa si interrompe durante la compilazione. Cercare di aggiungere volatile dopo il fatto è un po 'come cercare di aggiungere const dopo il fatto ... Doloroso.
jww

@ jww: è totalmente estraneo alle scritture fatte dal programma. Puoi prendere l'indirizzo di un oggetto di tipo T, memorizzarlo in un const T*e leggere da esso. Se crei quell'oggetto volatile, la memorizzazione del suo indirizzo in const T*fallirà, anche se non stai mai cercando di scrivere. volatilee le modifiche / modifiche / scritture in memoria dal codice del programma sono completamente ortogonali.
Ben Voigt

17

Un modo grezzo ma efficace di pensare la differenza è:

  • Il compilatore sa quando cambia un oggetto modificabile.
  • Il compilatore non può sapere quando un oggetto volatile cambia.

1
In questo senso: volatilebytes_received, mutablereference_count.
Mike DeSimone

11

Una variabile contrassegnata mutableconsente di modificarla in un metodo dichiarato const.

Una variabile contrassegnata volatiledice al compilatore che deve leggere / scrivere la variabile ogni volta che anche il tuo codice la dice (cioè non può ottimizzare gli accessi alla variabile).


4

Vorrei aggiungere che volatile è anche molto utile quando si ha a che fare con applicazioni multithreading, cioè si ha il thread principale (dove risiede main ()) e si genera un thread di lavoro che continuerà a girare mentre una variabile "app_running" è vera. main () controlla se "app_running" è vero o falso, quindi se non aggiungi l'attributo volatile alla dichiarazione di "app_running", se il compilatore ottimizza l'accesso a "app_running" nel codice eseguito dal thread secondario, main ( ) potrebbe cambiare "app_running" in false ma il thread secondario continuerà a funzionare perché il valore è stato memorizzato nella cache. Ho visto lo stesso comportamento usando gcc su Linux e VisualC ++. Un attributo "volatile" inserito nella dichiarazione "app_running" ha risolto il problema. Così,


1
No! Questo è un malinteso comune. C ++ 11 e C11 hanno introdotto gli atomici per questo scopo stackoverflow.com/questions/8819095/…
KristianR
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.