c++ - significado - variable volatile en c




¿La palabra clave 'mutable' tiene algún propósito que no sea permitir que la variable sea modificada por una función const? (12)

Bueno, sí, eso es lo que hace. Lo uso para miembros que se modifican mediante métodos que no cambian lógicamente el estado de una clase, por ejemplo, para acelerar las búsquedas implementando un caché:

class CIniWrapper
{
public:
   CIniWrapper(LPCTSTR szIniFile);

   // non-const: logically modifies the state of the object
   void SetValue(LPCTSTR szName, LPCTSTR szValue);

   // const: does not logically change the object
   LPCTSTR GetValue(LPCTSTR szName, LPCTSTR szDefaultValue) const;

   // ...

private:
   // cache, avoids going to disk when a named value is retrieved multiple times
   // does not logically change the public interface, so declared mutable
   // so that it can be used by the const GetValue() method
   mutable std::map<string, string> m_mapNameToValue;
};

Ahora, debe usar esto con cuidado: los problemas de concurrencia son una gran preocupación, ya que la persona que llama puede asumir que son seguros para subprocesos si solo usan métodos const . Y, por supuesto, la modificación de mutable datos mutable no debería cambiar el comportamiento del objeto de manera significativa, algo que podría violarse con el ejemplo que doy si, por ejemplo, se espera que los cambios escritos en el disco sean inmediatamente visibles para el la aplicación

Hace un tiempo me encontré con un código que marcaba una variable miembro de una clase con la palabra clave mutable . Por lo que puedo ver, simplemente te permite modificar una variable en un método const :

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 un boost::mutex como mutable, lo que permite que las funciones const lo bloqueen por motivos de seguridad de subprocesos, pero, para ser sincero, parece un poco pirateado.


El ejemplo clásico (como se mencionó en otras respuestas) y la única situación en la que he visto la palabra clave mutable utilizada hasta ahora, es para almacenar en caché el resultado de un método Get complicado, donde la caché se implementa como un miembro de datos de la clase y no como una 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 palabra clave mutable suelen ser una variable estática en el método o el truco const_cast .

Otra explicación detallada está here .


En algunos casos (como los iteradores mal diseñados), la clase necesita mantener un recuento o algún otro valor incidental, que realmente no afecte el "estado" principal de la clase. Esto es más a menudo donde veo utilizables mutables. Sin mutable, se vería obligado a sacrificar toda la constancia de su diseño.

Se siente como un hack la mayor parte del tiempo para mí también. Útil en muy pocas situaciones.


Es útil en situaciones en las que tiene un estado interno oculto, como un caché. Por ejemplo:

class HashTable
{
...
public:
    string lookup(string key) const
    {
        if(key == lastKey)
            return lastValue;

        string value = lookupInternal(key);

        lastKey = key;
        lastValue = value;

        return value;
    }

private:
    mutable string lastKey, lastValue;
};

Y luego puede tener un objeto const HashTable que aún use su método lookup() , que modifica el caché interno.


La palabra clave mutable es una forma de perforar la const que cubre sus objetos. Si tiene una referencia constante o un puntero a un objeto, no puede modificar ese objeto de ninguna manera, excepto cuándo y cómo se marca como mutable .

Con su referencia de const o puntero está limitado a:

  • Acceso de solo lectura para cualquier miembro de datos visible
  • permiso para llamar solo a los métodos que están marcados como const .

La excepción mutable hace para que ahora pueda escribir o establecer miembros de datos que estén marcados como mutable . Esa es la única diferencia externa visible.

Internamente, los métodos const que son visibles para usted también pueden escribir a los miembros de datos marcados como mutable . Esencialmente el velo constante se perfora de manera integral. Depende completamente del diseñador de API asegurarse de que mutable no destruya el concepto const y solo se use en casos especiales útiles. La palabra clave mutable ayuda porque marca claramente los miembros de datos que están sujetos a estos casos especiales.

En la práctica, puede utilizar const obsesiva en toda su base de código (esencialmente desea "infectar" su base de código con la "enfermedad" de const ). En este mundo, los punteros y las referencias son const con muy pocas excepciones, lo que genera un código que es más fácil de razonar y entender. Para una digresión interesante buscar "transparencia referencial".

Sin la palabra clave mutable , finalmente se verá obligado a utilizar const_cast para manejar los diversos casos especiales útiles que permite (almacenamiento en caché, recuento de referencias, depuración de datos, etc.). Desafortunadamente, const_cast es significativamente más destructivo que mutable porque obliga al cliente API a destruir la protección const de los objetos que está utilizando. Además, causa una destrucción generalizada const : la const_cast de un puntero o referencia constante permite la escritura sin restricciones y el acceso a los métodos a los miembros visibles. En contraste, mutable requiere que el diseñador de API ejerza un control detallado sobre las excepciones const , y generalmente estas excepciones están ocultas en los métodos const que operan en datos privados.

(Nota: me refiero a la visibilidad de los datos y los 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 trata here )


La palabra clave mutable es muy útil al crear apéndices para propósitos de prueba de clase. Puede anular una función de const y aún puede aumentar los contadores (mutables) o la funcionalidad de prueba que haya agregado a su apéndice. Esto mantiene intacta la interfaz de la clase aplastada.


Mutable es para marcar atributos específicos como modificables desde los métodos const . Ese es su único propósito. Piense con cuidado antes de usarlo, ya que su código probablemente será más limpio y más legible si cambia el diseño en lugar de usarlo mutable .

http://www.highprogrammer.com/alan/rants/mutable.html

Entonces, si la locura anterior no es para qué se puede cambiar, ¿para qué sirve? Aquí está el caso sutil: mutable es para el caso en el que un objeto es lógicamente constante, pero en la práctica debe cambiar. Estos casos son pocos y distantes entre sí, pero existen.

Los ejemplos que da el autor incluyen el almacenamiento en caché y las variables temporales de depuración.


Mutable se usa cuando tienes 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 bloqueo. Esta variable no cambia el comportamiento de la clase, pero es necesaria para implementar la seguridad de subprocesos de la clase en sí. 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 con el fin de hacer que una variable miembro sea escribible incluso por una función const.

El mutable especificado informa tanto al compilador como al lector de que es seguro y espera que una variable miembro pueda modificarse dentro de una función miembro const.


Su uso con boost :: mutex es exactamente para lo que está destinada esta palabra clave. Otro uso es para el almacenamiento interno de resultados para acelerar el acceso.

Básicamente, 'mutable' se aplica a cualquier atributo de clase que no afecte el estado visible externamente del objeto.

En el código de ejemplo de su pregunta, mutable podría ser inapropiado si el valor de done_ afecta el estado externo, depende de lo que esté en el ...; parte.


Su uso no es un hack, aunque como muchas otras cosas en C ++, mutable puede ser hack para un programador perezoso que no quiere volver atrás y marcar algo que no debería ser constante.


Use "mutable" cuando para cosas que son LOGICAMENTE sin estado para el usuario (y por lo tanto debe tener "const" getters en las API de la clase pública) pero NO son sin estado en la IMPLEMENTACIÓN subyacente (el código en su .cpp).

Los casos que uso con más frecuencia son la inicialización perezosa de miembros de "datos antiguos" sin estado. Es decir, es ideal en los casos estrechos cuando dichos miembros son caros, ya sea para compilar (procesador) o para transportar (memoria) y muchos usuarios del objeto nunca los pedirán. En esa situación, usted desea una construcción perezosa en el back-end para el rendimiento, ya que el 90% de los objetos construidos nunca tendrá que construirlos en absoluto, sin embargo, todavía debe presentar la API sin estado correcta para el consumo público.


mutable se utiliza principalmente en un detalle de implementación de la clase. El usuario de la clase no necesita saberlo, por lo tanto, el método que él piensa "debería" ser constante puede ser. Su ejemplo de tener un mutex ser mutable es un buen ejemplo canónico.







mutable