volátil vs. mutável em C ++

86

Tenho uma pergunta sobre a diferença entre volátil e mutável. Percebi que os dois significam que ele pode ser alterado. O quê mais? Eles são a mesma coisa? Qual é a diferença? Onde eles são aplicáveis? Por que as duas idéias são propostas? Como usá-los de maneira diferente?

Muito obrigado.

porta do céu
fonte

Respostas:

113

Um mutablecampo pode ser alterado até mesmo em um objeto acessado por meio de um constponteiro ou referência, ou em um constobjeto, de forma que o compilador saiba que não deve ser armazenado na memória R / O. Uma volatilelocalização é aquela que pode ser alterada por código que o compilador não conhece (por exemplo, algum driver de nível de kernel), então o compilador sabe que não deve otimizar, por exemplo, atribuição de registro desse valor sob a suposição inválida de que o valor "não pode ter alterado "desde que foi carregado pela última vez nesse registro. Informações muito diferentes fornecidas ao compilador para impedir tipos muito diferentes de otimizações inválidas.

Alex Martelli
fonte
13
volatileos objetos também podem ser alterados por processos que não envolvem a CPU. Por exemplo, um registro de bytes recebidos em um periférico de comunicação pode incrementar-se no recebimento de um byte (e isso pode até disparar uma interrupção). Outro exemplo é um registro de sinalizadores de interrupções pendentes em um periférico.
Mike DeSimone,
56
Além disso, volatilenão significa apenas que o objeto pode mudar fora do conhecimento do compilador - também significa que as gravações no objeto não podem ser eliminadas pelo compilador, mesmo se essas gravações parecerem inúteis. Por exemplo: x = 1; x = 0; se xfor volátil, o compilador deve emitir ambas as operações de gravação (que podem ser significativas no nível do hardware). No entanto, para um objeto não volátil, o compilador pode escolher não se preocupar em escrever o, 1pois ele nunca é usado.
Michael Burr
15
Um objeto pode ser marcado com conste volatile! Você não pode alterar o objeto, mas ele pode ser alterado nas suas costas.
CTMacUser
2
@Destructor: a situação usual é para gravações em um registro de dispositivo de hardware.
Michael Burr
5
@Destructor, digamos que você esteja controlando o status de um LED. Escrever 0 desliga-o, escrever 1 liga-o. Se eu precisar piscar o LED para comunicar algum status de erro, mas o compilador decidir otimizar todas as gravações, exceto a última, já que nenhum dos valores está sendo usado, então o LED nunca pisca e o comportamento que desejo não é realizado .
iheanyi
28

mutable: A palavra-chave mutável substitui qualquer instrução const envolvente. Um membro mutável de um objeto const pode ser modificado.

volatile: A palavra-chave volatile é um modificador dependente da implementação, usado ao declarar variáveis, o que impede o compilador de otimizar essas variáveis. Volátil deve ser usado com variáveis ​​cujo valor pode mudar de maneiras inesperadas (ou seja, por meio de uma interrupção), o que pode entrar em conflito com otimizações que o compilador pode realizar.

Fonte

xian
fonte
você disse Volatile should be used with variables whose value can change in unexpected waysque deveríamos preferir usá-lo com aleatório?
Asif Mushtaq de
@AsifMushtaq não valores. maneiras. mutável afeta as permissões que o código que você escreve tem. Portanto, você pode acessar a variável por meio de um ptr const ou referência const. E se não for o seu código alterando isso? Algo que o compilador não consegue verificar o tipo de ptr ou de referência? Isso é volátil. E o volátil também força a gravação do cache de volta na memória principal. Portanto, isso é muito usado com código multithread. :)
Dan
22

Eles definitivamente NÃO são a mesma coisa. Mutable interage com const. Se você tiver um ponteiro const, normalmente não poderá alterar os membros. Mutable fornece uma exceção a essa regra.

O volátil, por outro lado, não tem nenhuma relação com as mudanças feitas pelo programa. Isso significa que a memória pode mudar por motivos fora do controle do compilador, portanto, o compilador tem que ler ou escrever o endereço da memória todas as vezes e não pode armazenar o conteúdo em um registro.

Ben Voigt
fonte
"Volátil, por outro lado, não tem nenhuma relação com as mudanças feitas pelo programa ..." - hmmm, torne um membro volátil e veja o que quebra durante a compilação. Tentar adicionar voláteis após o fato é muito parecido com tentar adicionar const após o fato ... Doloroso.
jww
@jww: Não tem nenhuma relação com as gravações feitas pelo programa. Você pode pegar o endereço de um objeto do tipo T, armazená-lo em um const T*e ler a partir dele. Se você criar esse objeto volatile, o armazenamento de seu endereço em const T*falhará, mesmo que você nunca tente escrever. volatilee as alterações / modificações / gravações na memória do código do programa são completamente ortogonais.
Ben Voigt de
17

Uma maneira rude, mas eficaz de pensar na diferença é:

  • O compilador sabe quando um objeto mutável muda.
  • O compilador não pode saber quando um objeto volátil muda.
Jonathan Leffler
fonte
1
Nesse sentido: volatilebytes_received, mutablereference_count.
Mike DeSimone,
11

Uma variável marcada mutablepermite que ela seja modificada em um método declarado const.

Uma variável marcada volatilediz ao compilador que ele deve ler / escrever a variável toda vez que seu código a disser (ou seja, ele não pode otimizar acessos de distância à variável).

Kyle Lutz
fonte
4

Eu gostaria de acrescentar que volatile também é muito útil ao lidar com aplicativos multithreading, ou seja, você tem seu thread principal (onde main () vive) e você gera um thread de trabalho que continuará girando enquanto uma variável "app_running" é verdadeira. main () controla se "app_running" é verdadeiro ou falso, então, se você não adicionar o atributo volatile à declaração de "app_running", se o compilador otimizar o acesso a "app_running" no código executado pelo thread secundário, principal ( ) pode alterar "app_running" para false, mas o thread secundário continuará em execução porque o valor foi armazenado em cache. Eu vi o mesmo comportamento usando gcc no Linux e VisualC ++. Um atributo "volatile" colocado na declaração "app_running" resolveu o problema. Então,

BinCoder
fonte
1
Não! Este é um mal-entendido comum. C ++ 11 e C11 introduziram atomics para este propósito stackoverflow.com/questions/8819095/…
KristianR