Hace un tiempo me encontré con un código que marcaba una variable miembro de una clase con la mutable
palabra clave. Por lo que puedo ver, simplemente le permite modificar una variable en un const
método:
class Foo
{
private:
mutable bool done_;
public:
void doSomething() const { ...; done_ = true; }
};
¿Es este el único uso de esta palabra clave o hay más de lo que parece? Desde entonces, he usado esta técnica en una clase, marcando boost::mutex
como mutable permitiendo que las const
funciones lo bloqueen por razones de seguridad de subprocesos, pero, para ser honesto, se siente como un truco.
mutable
: stackoverflow.com/questions/15999123/…const
(de tipos), por lo que no tengo que hacer esto:class A_mutable{}; using A = A_mutable const; mutable_t<A> a;
si quiero const por defecto, es decirmutable A a;
(mutable explícito) yA a;
(const implícito).Respuestas:
Permite la diferenciación de const bit a bit y const lógico. Const lógico es cuando un objeto no cambia de manera visible a través de la interfaz pública, como su ejemplo de bloqueo. Otro ejemplo sería una clase que calcula un valor la primera vez que se solicita y almacena en caché el resultado.
Dado que c ++ 11
mutable
se puede usar en una lambda para denotar que las cosas capturadas por valor son modificables (no lo son por defecto):fuente
x
dentro del lambda permanece dentro del lambda, es decir, la función lambda solo puede modificar su propia copia dex
. El cambio no es visible en el exterior, el originalx
aún no ha cambiado. Considere que las lambdas se implementan como clases functor; Las variables capturadas corresponden a las variables miembro.La
mutable
palabra clave es una forma de perforar elconst
velo que cubre con sus objetos. Si tiene una referencia constante o puntero a un objeto, no puede modificar ese objeto de ninguna manera, excepto cuándo y cómo está marcadomutable
.Con su
const
referencia o puntero, está obligado a:const
.La
mutable
excepción hace que ahora pueda escribir o establecer miembros de datos que están marcadosmutable
. Esa es la única diferencia externamente visible.Internamente, los
const
métodos que son visibles para usted también pueden escribir en los miembros de datos que están marcadosmutable
. Esencialmente, el velo constante está perforado de manera integral. Depende completamente del diseñador de API asegurarse de quemutable
no destruya elconst
concepto y solo se use en casos especiales útiles. Lamutable
palabra clave ayuda porque marca claramente a los miembros de datos que están sujetos a estos casos especiales.En la práctica, puede usarlo
const
obsesivamente en toda su base de código (esencialmente desea "infectar" su base de código con laconst
"enfermedad"). En este mundo, los punteros y las referencias sonconst
con muy pocas excepciones, produciendo código que es más fácil de razonar y entender. Para una digresión interesante, busque "transparencia referencial".Sin la
mutable
palabra clave, eventualmente se verá obligado a usarconst_cast
para manejar los diversos casos especiales útiles que permite (almacenamiento en caché, recuento de referencias, datos de depuración, etc.). Desafortunadamente,const_cast
es significativamente más destructivo quemutable
porque obliga al cliente API a destruir laconst
protección de los objetos que está utilizando. Además, causa unaconst
destrucción generalizada : el usoconst_cast
de un puntero o referencia constante permite la escritura sin restricciones y el método de acceso a miembros visibles. Por el contrario,mutable
requiere que el diseñador de la API ejerza un control preciso sobre lasconst
excepciones y, por lo general, estas excepciones están ocultas en losconst
métodos que funcionan con datos privados.(Nota: me refiero a la visibilidad de datos y métodos varias veces. Estoy hablando de miembros marcados como públicos frente a privados o protegidos, que es un tipo de protección de objetos totalmente diferente que se analiza aquí ).
fuente
const_cast
para modificar una parte de unconst
objeto produce un comportamiento indefinido.const_cast
para implementar la mutación de las variables miembro en unconst
método, que no le pediría el cliente al hacer el reparto - que lo haría dentro del método por elconst_cast
ingthis
. Básicamente, le permite evitar la constidad en miembros arbitrarios en un sitio de llamada específico , mientrasmutable
que le permite eliminar la const en un miembro específico en todos los sitios de llamada. Esto último suele ser lo que desea para el uso típico (almacenamiento en caché, estadísticas), pero a veces const_cast se ajusta al patrón.const_cast
patrón se ajusta mejor en algunos casos, como cuando desea modificar temporalmente un miembro y luego restaurarlo (más o menos comoboost::mutex
). El método es lógicamente constante ya que el estado final es el mismo que el inicial, pero desea realizar ese cambio transitorio.const_cast
puede ser útil allí porque le permite deshacerse de la constante específicamente en ese método donde se deshaga la mutación, peromutable
no sería tan apropiada ya que eliminaría la protección constante de todos los métodos, que no necesariamente siguen el "do , deshacer "patrón.const_cast
una posible bomba de tiempo.mutable
no tiene ese problema ya que dichos objetos no se pueden colocar en la memoria de solo lectura.Su uso con boost :: mutex es exactamente para lo que esta palabra clave está destinada. Otro uso es para el almacenamiento en caché interno de resultados para acelerar el acceso.
Básicamente, 'mutable' se aplica a cualquier atributo de clase que no afecte el estado externamente visible del objeto.
En el código de muestra en su pregunta, mutable puede ser inapropiado si el valor de done_ afecta el estado externo, depende de lo que esté en el ...; parte.
fuente
Mutable es para marcar un atributo específico como modificable desde dentro de los
const
métodos. Ese es su único propósito. Piensa cuidadosamente antes de usarlo, porque tu código probablemente será más limpio y más legible si cambias el diseño en lugar de usarlomutable
.http://www.highprogrammer.com/alan/rants/mutable.html
Los ejemplos que da el autor incluyen el almacenamiento en caché y las variables de depuración temporales.
fuente
mutable
puede hacer que el código sea más legible y limpio. En el siguiente ejemplo,read
puede serconst
como se esperaba. `mutable m_mutex; Contenedor m_container; void add (Item item) {Lockguard lock (m_mutex); m_container.pushback (artículo); } Elemento read () const {Lockguard lock (m_mutex); return m_container.first (); } `Es útil en situaciones en las que tiene estado interno oculto, como un caché. Por ejemplo:
Y luego puede hacer que un
const HashTable
objeto todavía use sulookup()
método, que modifica la memoria caché interna.fuente
mutable
existe como se infiere para permitir que uno modifique datos en una función constante.La intención es que pueda tener una función que "no haga nada" en el estado interno del objeto, por lo que debe marcar la función
const
, pero es posible que necesite modificar algunos de los objetos de manera que no afecten su correcto funcionalidadLa palabra clave puede actuar como una pista para el compilador: un compilador teórico podría colocar un objeto constante (como un global) en la memoria que se marcó como de solo lectura. La presencia de
mutable
indicios de que esto no debe hacerse.Aquí hay algunas razones válidas para declarar y usar datos mutables:
mutable boost::mutex
es perfectamente razonable.fuente
const
(y dicha inspección tendrá éxito o fallará independientemente deconst
omutable
). Simplemente declarar la funciónconst
no es suficiente: unaconst
función es libre de tener efectos secundarios como modificar una variable global o algo que se pasa a la función, por lo que no es una garantía útil para esa prueba.const
palabra clave en C ++.Bueno, sí, eso es lo que hace. Lo uso para miembros que son modificados por métodos que no cambian lógicamente el estado de una clase, por ejemplo, para acelerar las búsquedas mediante la implementación de un caché:
Ahora, debe usar esto con cuidado: los problemas de concurrencia son una gran preocupación, ya que una persona que llama podría asumir que son seguros para subprocesos si solo usa
const
métodos. Y, por supuesto, la modificación demutable
datos no debería cambiar el comportamiento del objeto de manera significativa, algo que podría ser violado por el ejemplo que di si, por ejemplo, se espera que los cambios escritos en el disco sean visibles de inmediato para la aplicación .fuente
Mutable se usa cuando tiene una variable dentro de la clase que solo se usa dentro de esa clase para señalar cosas como, por ejemplo, un mutex o un candado. Esta variable no cambia el comportamiento de la clase, pero es necesaria para implementar la seguridad de subprocesos de la clase misma. Por lo tanto, si sin "mutable", no podría tener funciones "const" porque esta variable deberá cambiarse en todas las funciones que están disponibles para el mundo exterior. Por lo tanto, mutable se introdujo para hacer que una variable miembro se pueda escribir incluso mediante una función const.
fuente
mutable se usa principalmente en un detalle de implementación de la clase. El usuario de la clase no necesita saberlo, por lo tanto, el método cree que "debería" ser constante. Su ejemplo de que un mutex sea mutable es un buen ejemplo canónico.
fuente
Su uso no es un truco, aunque, como muchas cosas en C ++, mutable puede ser pirateado para un programador perezoso que no quiere regresar y marcar algo que no debería ser constante como no constante.
fuente
Use "mutable" cuando para cosas que son LÓGICAMENTE sin estado para el usuario (y por lo tanto deberían tener captadores "constantes" en las API de la clase pública) pero NO son apátridas en la IMPLEMENTACIÓN subyacente (el código en su .cpp).
Los casos que lo uso con más frecuencia son la inicialización diferida de miembros sin estado de "datos antiguos". Es decir, es ideal en los casos estrechos cuando tales miembros son caros de construir (procesador) o llevar (memoria) y muchos usuarios del objeto nunca los pedirán. En esa situación, desea una construcción perezosa en el back-end para el rendimiento, ya que el 90% de los objetos construidos nunca necesitarán construirlos, pero aún debe presentar la API sin estado correcta para el consumo público.
fuente
Mutable cambia el significado de
const
const bit a const lógico para la clase.Esto significa que las clases con miembros mutables ya no serán constantes y no aparecerán en las secciones de solo lectura del ejecutable.
Además, modifica la verificación de tipos al permitir que las
const
funciones miembro cambien miembros mutables sin usarconst_cast
.Consulte las otras respuestas para obtener más detalles, pero quería resaltar que no se trata simplemente de seguridad de tipos y que afecta el resultado compilado.
fuente
En algunos casos (como iteradores mal diseñados), la clase necesita mantener un conteo u otro valor incidental, que realmente no afecta el "estado" principal de la clase. Esto es más a menudo donde veo mutable utilizado. Sin mutable, se vería obligado a sacrificar toda la coherencia de su diseño.
También me parece un truco la mayor parte del tiempo. Útil en muy, muy pocas situaciones.
fuente
El ejemplo clásico (como se menciona en otras respuestas) y la única situación en la que he visto la
mutable
palabra clave utilizada hasta ahora, es para almacenar en caché el resultado de un proceso complicado.Get
método , donde el caché se implementa como un miembro de datos de la clase y no como un variable estática en el método (por razones de compartir entre varias funciones o limpieza simple).En general, las alternativas al uso de la
mutable
palabra clave suelen ser una variable estática en el método o elconst_cast
truco.Otra explicación detallada está aquí .
fuente
const_cast
es solo para cuando sepa (o haya sido garantizado) que algo no cambiará (por ejemplo, cuando interfiere con las bibliotecas C) o cuando sabe que no se declaró const. Es decir, la modificación de una variable constante const genera resultados indefinidos.const_cast
se puede usar para modificar un miembro de la clase en unconst
método, que es a lo que me referí ...const_cast
, como se dijo, esto solo se permite cuando el objeto no se declaróconst
. Por ejemploconst Frob f; f.something();
, convoid something() const { const_cast<int&>(m_foo) = 2;
resultados en comportamiento indefinido.El mutable puede ser útil cuando está anulando una función virtual constante y desea modificar su variable miembro de clase secundaria en esa función. En la mayoría de los casos, no querrá alterar la interfaz de la clase base, por lo que debe usar su propia variable de miembro mutable.
fuente
La palabra clave mutable es muy útil al crear apéndices para fines de prueba de clase. Puede desactivar una función constante y aún puede aumentar los contadores (mutables) o cualquier funcionalidad de prueba que haya agregado a su código auxiliar. Esto mantiene intacta la interfaz de la clase stubbed.
fuente
Uno de los mejores ejemplos donde usamos mutable es, en copia profunda. En el constructor de copia enviamos
const &obj
como argumento. Por lo tanto, el nuevo objeto creado será de tipo constante. Si queremos cambiar (en su mayoría no cambiaremos, en casos excepcionales podemos cambiar) los miembros en este objeto constante creado recientemente, debemos declararlo comomutable
.mutable
La clase de almacenamiento solo se puede usar en un miembro de datos no estático y no constante de una clase. El miembro de datos mutables de una clase se puede modificar incluso si es parte de un objeto que se declara como constante.En el ejemplo anterior, podemos cambiar el valor de la variable miembro
x
aunque sea parte de un objeto que se declara como constante. Esto se debe a que la variablex
se declara como mutable. Pero si intenta modificar el valor de la variable miembroy
, el compilador arrojará un error.fuente
La palabra clave 'mutable' es en realidad una palabra clave reservada. A menudo se usa para variar el valor de la variable constante. Si desea tener múltiples valores de una constante, use la palabra clave mutable.
fuente