Há algum tempo, deparei-me com um código que marcava uma variável de membro de uma classe com a mutable
palavra - chave. Tanto quanto posso ver, simplesmente permite modificar uma variável em um const
método:
class Foo
{
private:
mutable bool done_;
public:
void doSomething() const { ...; done_ = true; }
};
É o único uso dessa palavra-chave ou existe mais do que aparenta? Desde então, usei essa técnica em uma classe, marcando uma boost::mutex
função mutável como permitida const
para bloqueá-la por motivos de segurança de encadeamento, mas, para ser sincero, parece um hack.
mutable
- chave : stackoverflow.com/questions/15999123/…const
(de tipos), para que eu não precise fazer issoclass A_mutable{}; using A = A_mutable const; mutable_t<A> a;
:, se eu quiser const-por-default, ou sejamutable A a;
(mutável explícito) eA a;
(const implícita).Respostas:
Permite a diferenciação de const bit a bit e const lógico. Const lógico é quando um objeto não muda de uma maneira que seja visível através da interface pública, como no seu exemplo de bloqueio. Outro exemplo seria uma classe que calcula um valor na primeira vez em que é solicitado e armazena em cache o resultado.
Como o c ++ 11
mutable
pode ser usado em um lambda para indicar que as coisas capturadas por valor são modificáveis (elas não são por padrão):fonte
x
dentro do lambda permanece dentro do lambda, ou seja, a função lambda só pode modificar sua própria cópiax
. A alteração não é visível do lado de fora, o originalx
ainda permanece inalterado. Considere que lambdas são implementadas como classes de functor; variáveis capturadas correspondem a variáveis membro.A
mutable
palavra-chave é uma maneira de perfurar oconst
véu que você coloca sobre seus objetos. Se você tiver uma referência const ou ponteiro para um objeto, não poderá modificar esse objeto de nenhuma maneira, exceto quando e como está marcadomutable
.Com sua
const
referência ou ponteiro, você está limitado a:const
.A
mutable
exceção permite que você agora possa gravar ou definir membros de dados marcadosmutable
. Essa é a única diferença visível externamente.Internamente, os
const
métodos visíveis para você também podem gravar nos membros de dados marcadosmutable
. Essencialmente, o véu const é perfurado de forma abrangente. Cabe ao projetista da API garantir quemutable
isso não destrua oconst
conceito e seja usado apenas em casos especiais úteis. Amutable
palavra-chave ajuda porque marca claramente os membros de dados que estão sujeitos a esses casos especiais.Na prática, você pode usar
const
obsessivamente em toda a sua base de código (você deseja essencialmente "infectar" sua base de código com aconst
"doença"). Neste mundo, ponteiros e referências sãoconst
muito poucas exceções, produzindo código mais fácil de raciocinar e entender. Para uma digressão interessante, procure "transparência referencial".Sem a
mutable
palavra-chave, você será forçado a usarconst_cast
para lidar com os vários casos especiais úteis que ela permite (armazenamento em cache, contagem de referências, dados de depuração etc.). Infelizmente,const_cast
é significativamente mais destrutivo do quemutable
porque força o cliente da API a destruir aconst
proteção dos objetos que ele está usando. Além disso, causaconst
destruição generalizada : o uso deconst_cast
um ponteiro ou referência constante permite acesso irrestrito à gravação e à chamada de método a membros visíveis. Por outro lado,mutable
exige que o designer da API exerça controle refinado sobre asconst
exceções e, geralmente, essas exceções estão ocultas nosconst
métodos que operam com dados particulares.(NB refiro-me à visibilidade de dados e métodos algumas vezes. Estou falando de membros marcados como públicos versus privados ou protegidos, que é um tipo totalmente diferente de proteção a objetos discutido aqui .)
fonte
const_cast
para modificar uma parte de umconst
objeto gera um comportamento indefinido.const_cast
para implementar a mutação de variáveis-membro em umconst
método, não pediria ao cliente para fazer a conversão - você faria isso dentro do método usandoconst_cast
ingthis
. Basicamente, permite ignorar a constância em membros arbitrários em um site de chamada específico , enquantomutable
vamos remover a const em um membro específico em todos os sites de chamada. O último é geralmente o que você deseja para o uso típico (armazenamento em cache, estatísticas), mas às vezes o const_cast se encaixa no padrão.const_cast
padrão se encaixa melhor em alguns casos, como quando você deseja modificar temporariamente um membro e depois restaurá-lo (praticamente comoboost::mutex
). O método é logicamente constante, pois o estado final é o mesmo que o inicial, mas você deseja fazer essa alteração transitória.const_cast
pode ser útil lá, porque permite que você expulte const especificamente nesse método, caso a mutação seja desfeita, masmutable
não seria tão apropriada, pois removeria a proteção const de todos os métodos, que nem sempre seguem o "do , desfazer "padrão.const_cast
possível uma bomba-relógio.mutable
não tem esse problema, pois esses objetos não podem ser colocados na memória somente leitura.Seu uso com o boost :: mutex é exatamente o objetivo dessa palavra-chave. Outro uso é o cache interno de resultados para acelerar o acesso.
Basicamente, 'mutável' se aplica a qualquer atributo de classe que não afeta o estado visível externamente do objeto.
No código de exemplo da sua pergunta, mutable pode ser inadequado se o valor de done_ afetar o estado externo, depende do que está no ...; parte.
fonte
Mutável é para marcar atributos específicos como modificáveis a partir de
const
métodos. Esse é o seu único objetivo. Pense com cuidado antes de usá-lo, porque seu código provavelmente será mais limpo e legível se você alterar o design em vez de usá-lomutable
.http://www.highprogrammer.com/alan/rants/mutable.html
Exemplos que o autor fornece incluem variáveis de cache e depuração temporária.
fonte
mutable
pode tornar o código mais legível e limpo. No exemplo a seguir,read
pode serconst
o esperado. `m_mutex mutável; Contêiner m_container; void add (item do item) {Lockguard lock (m_mutex); m_container.pushback (item); } Item read () const {Lockguard lock (m_mutex); retornar m_container.first (); } `É útil em situações em que você oculta um estado interno, como um cache. Por exemplo:
E então você pode ter um
const HashTable
objeto ainda usando seulookup()
método, que modifica o cache interno.fonte
mutable
existe à medida que você deduz que permite modificar dados em uma função constante.A intenção é que você possa ter uma função que "não faça nada" para o estado interno do objeto e, assim, marque a função
const
, mas poderá realmente precisar modificar alguns dos objetos de maneira que não afetem seu correto funcionalidade.A palavra-chave pode atuar como uma dica para o compilador - um compilador teórico pode colocar um objeto constante (como um global) na memória que foi marcada como somente leitura. A presença de
mutable
dicas de que isso não deve ser feito.Aqui estão alguns motivos válidos para declarar e usar dados mutáveis:
mutable boost::mutex
é perfeitamente razoável.fonte
const
(e essa inspeção terá êxito ou falhará, independentemente deconst
oumutable
). Simplesmente declarar a funçãoconst
não é suficiente: umaconst
função é livre para ter efeitos colaterais, como modificar uma variável global ou algo passado para a função, portanto, não é uma garantia útil para essa prova.const
palavra - chave em C ++.Bem, sim, é isso que faz. Eu o uso para membros modificados por métodos que não alteram logicamente o estado de uma classe - por exemplo, para acelerar as pesquisas implementando um cache:
Agora, você deve usá-lo com cuidado - os problemas de simultaneidade são uma grande preocupação, pois um chamador pode assumir que eles são seguros para threads, apenas usando
const
métodos. E, é claro, modificarmutable
dados não deve alterar o comportamento do objeto de maneira significativa, algo que poderia ser violado pelo exemplo que eu dei, por exemplo, se se esperava que as alterações gravadas no disco fossem imediatamente visíveis para o aplicativo .fonte
Mutable é usado quando você tem uma variável dentro da classe que é usada apenas nessa classe para sinalizar coisas como, por exemplo, um mutex ou um bloqueio. Essa variável não altera o comportamento da classe, mas é necessária para implementar a segurança do encadeamento da própria classe. Portanto, se sem "mutável", você não seria capaz de ter funções "const" porque essa variável precisará ser alterada em todas as funções disponíveis para o mundo externo. Portanto, mutable foi introduzido para tornar uma variável membro gravável mesmo por uma função const.
fonte
mutable é usado principalmente em um detalhe de implementação da classe. O usuário da classe não precisa saber disso, portanto, o método que ele acha que "deveria" ser const pode ser. Seu exemplo de ter um mutex mutável é um bom exemplo canônico.
fonte
Seu uso não é um hack, embora, como muitas coisas em C ++, o mutable possa ser hack para um programador preguiçoso que não queira voltar e marcar algo que não deve ser const como não-const.
fonte
Use "mutable" quando para coisas que são LOGICALLY sem estado para o usuário (e, portanto, devem ter getters "const" nas APIs da classe pública), mas NÃO são sem estado na IMPLEMENTATION subjacente (o código no seu .cpp).
Os casos que eu o uso com mais frequência são a inicialização lenta de membros sem estado "simples de dados antigos". Nomeadamente, é ideal nos casos limitados em que esses membros são caros para construir (processador) ou transportar (memória) e muitos usuários do objeto nunca os solicitarão. Nessa situação, você deseja uma construção lenta no back-end para obter desempenho, já que 90% dos objetos criados nunca precisarão compilá-los, mas você ainda precisará apresentar a API sem estado correta para consumo público.
fonte
Mutable altera o significado de
const
const bit a bit para const lógico para a classe.Isso significa que as classes com membros mutáveis são mais constantes em bits e não aparecerão mais nas seções somente leitura do executável.
Além disso, modifica a verificação de tipo, permitindo que as
const
funções de membro alterem membros mutáveis sem usarconst_cast
.Veja as outras respostas para obter mais detalhes, mas eu gostaria de destacar que não é apenas para segurança de tipo e que afeta o resultado compilado.
fonte
Em alguns casos (como iteradores mal projetados), a classe precisa manter uma contagem ou algum outro valor incidental, que realmente não afeta o "estado" principal da classe. É na maioria das vezes que vejo mutável usado. Sem mutável, você seria forçado a sacrificar toda a constância de seu design.
Parece um hack a maior parte do tempo para mim também. Útil em muito poucas situações.
fonte
O exemplo clássico (como mencionado em outras respostas) e a única situação em que vi a
mutable
palavra - chave usada até agora, é para armazenar em cache o resultado de uma tarefa complicada.Get
método , em que o cache é implementado como um membro de dados da classe e não como um variável estática no método (por razões de compartilhamento entre várias funções ou limpeza simples).Em geral, as alternativas ao uso da
mutable
palavra - chave geralmente são uma variável estática no método ou noconst_cast
truque.Outra explicação detalhada está aqui .
fonte
const_cast
é somente quando você souber (ou tiver sido garantido) que algo não será alterado (por exemplo, ao interferir nas bibliotecas C) ou quando você souber que não foi declarado const. Ou seja, a modificação de uma variável constante constante resulta em um comportamento indefinido.const_cast
pode ser usado para modificar um membro da classe em umconst
método, que é o que me referi ...const_cast
, como dito, isso só é permitido quando o objeto não foi declaradoconst
. Por exemploconst Frob f; f.something();
, comvoid something() const { const_cast<int&>(m_foo) = 2;
resultados em comportamento indefinido.O mutável pode ser útil quando você está substituindo uma função virtual const e deseja modificar sua variável de membro da classe filho nessa função. Na maioria dos casos, você não deseja alterar a interface da classe base, portanto, você deve usar sua própria variável de membro mutável.
fonte
A palavra-chave mutável é muito útil ao criar stubs para fins de teste de classe. Você pode stub uma função const e ainda conseguir aumentar contadores (mutáveis) ou qualquer funcionalidade de teste que você adicionou ao seu stub. Isso mantém intacta a interface da classe stubbed.
fonte
Um dos melhores exemplos em que usamos mutable é, em cópia profunda. no construtor copy, enviamos
const &obj
como argumento. Portanto, o novo objeto criado será do tipo constante. Se queremos mudar (na maioria das vezes não mudamos, em casos raros, podemos mudar) os membros desse objeto const recém-criado, precisamos declará-lo comomutable
.mutable
A classe de armazenamento pode ser usada apenas no membro de dados não estático e não const de uma classe. O membro de dados mutáveis de uma classe pode ser modificado mesmo que faça parte de um objeto declarado como const.No exemplo acima, somos capazes de alterar o valor da variável membro,
x
embora faça parte de um objeto declarado como const. Isso ocorre porque a variávelx
é declarada como mutável. Mas se você tentar modificar o valor da variável membroy
, o compilador lançará um erro.fonte
A própria palavra-chave 'mutável' é na verdade uma palavra-chave reservada. Em seguida, é usada para variar o valor da variável constante. Se você deseja ter vários valores de um constsnt, use a palavra-chave mutável.
fonte