Hace un tiempo me encontré con un código que marcaba una variable miembro de una clase con la mutablepalabra clave. Por lo que puedo ver, simplemente le permite modificar una variable en un constmé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::mutexcomo mutable permitiendo que las constfunciones 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
mutablese puede usar en una lambda para denotar que las cosas capturadas por valor son modificables (no lo son por defecto):fuente
xdentro 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 originalxaún no ha cambiado. Considere que las lambdas se implementan como clases functor; Las variables capturadas corresponden a las variables miembro.La
mutablepalabra clave es una forma de perforar elconstvelo 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
constreferencia o puntero, está obligado a:const.La
mutableexcepción hace que ahora pueda escribir o establecer miembros de datos que están marcadosmutable. Esa es la única diferencia externamente visible.Internamente, los
constmé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 quemutableno destruya elconstconcepto y solo se use en casos especiales útiles. Lamutablepalabra clave ayuda porque marca claramente a los miembros de datos que están sujetos a estos casos especiales.En la práctica, puede usarlo
constobsesivamente 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 sonconstcon 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
mutablepalabra clave, eventualmente se verá obligado a usarconst_castpara manejar los diversos casos especiales útiles que permite (almacenamiento en caché, recuento de referencias, datos de depuración, etc.). Desafortunadamente,const_castes significativamente más destructivo quemutableporque obliga al cliente API a destruir laconstprotección de los objetos que está utilizando. Además, causa unaconstdestrucción generalizada : el usoconst_castde un puntero o referencia constante permite la escritura sin restricciones y el método de acceso a miembros visibles. Por el contrario,mutablerequiere que el diseñador de la API ejerza un control preciso sobre lasconstexcepciones y, por lo general, estas excepciones están ocultas en losconstmé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_castpara modificar una parte de unconstobjeto produce un comportamiento indefinido.const_castpara implementar la mutación de las variables miembro en unconstmétodo, que no le pediría el cliente al hacer el reparto - que lo haría dentro del método por elconst_castingthis. Básicamente, le permite evitar la constidad en miembros arbitrarios en un sitio de llamada específico , mientrasmutableque 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_castpatró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_castpuede ser útil allí porque le permite deshacerse de la constante específicamente en ese método donde se deshaga la mutación, peromutableno 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_castuna posible bomba de tiempo.mutableno 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
constmé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
mutablepuede hacer que el código sea más legible y limpio. En el siguiente ejemplo,readpuede serconstcomo 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:
clase HashTable { ... público: cadena de búsqueda (clave de cadena) const { if (clave == lastKey) return lastValue; valor de cadena = lookupInternal (clave); lastKey = clave; lastValue = value; valor de retorno; } privado: cadena mutable lastKey, lastValue; };Y luego puede hacer que un
const HashTableobjeto todavía use sulookup()método, que modifica la memoria caché interna.fuente
mutableexiste 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
mutableindicios de que esto no debe hacerse.Aquí hay algunas razones válidas para declarar y usar datos mutables:
mutable boost::mutexes perfectamente razonable.fuente
const(y dicha inspección tendrá éxito o fallará independientemente deconstomutable). Simplemente declarar la funciónconstno es suficiente: unaconstfunció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.constpalabra 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
constmétodos. Y, por supuesto, la modificación demutabledatos 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
constconst 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
constfunciones 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
mutablepalabra clave utilizada hasta ahora, es para almacenar en caché el resultado de un proceso complicado.Getmé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
mutablepalabra clave suelen ser una variable estática en el método o elconst_casttruco.Otra explicación detallada está aquí .
fuente
const_castes 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_castse puede usar para modificar un miembro de la clase en unconstmé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 &objcomo 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.mutableLa 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
xaunque sea parte de un objeto que se declara como constante. Esto se debe a que la variablexse 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