¿Tiene la palabra clave 'mutable' algún otro propósito además de permitir que una función de miembro constante modifique un miembro de datos?

Resuelto Rob asked hace 15 años • 18 respuestas

Hace un tiempo, encontré un código que marcaba un miembro de datos de una clase con la mutablepalabra clave. Por lo que puedo ver, simplemente le permite modificar un miembro en un constmétodo de miembro calificado:

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::mutexas mutable, permitiendo que constlas funciones lo bloqueen por razones de seguridad de subprocesos, pero, para ser honesto, parece un truco.

Rob avatar Sep 20 '08 02:09 Rob
Aceptado

Permite la diferenciación de constante bit a bit y constante lógica. La constante lógica es cuando un objeto no cambia de una manera que sea visible a través de la interfaz pública, como en el 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 indicar que las cosas capturadas por valor son modificables (no lo son de forma predeterminada):

int x = 0;
auto f1 = [=]() mutable {x = 42;};  // OK
auto f2 = [=]()         {x = 42;};  // Error: a by-value capture cannot be modified in a non-mutable lambda
KeithB avatar Sep 19 '2008 20:09 KeithB

La mutablepalabra clave es una forma de perforar el constvelo que cubres tus 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 está marcado mutable.

Con su constreferencia o puntero está obligado a:

  • Solo acceso de lectura para cualquier miembro de datos visible.
  • permiso para llamar sólo a métodos marcados como const.

La mutableexcepción hace que ahora pueda escribir o configurar miembros de datos que estén marcados mutable. Esa es la única diferencia visible externamente.

Internamente, aquellos constmétodos que son visibles para usted también pueden escribir en miembros de datos que están marcados mutable. Básicamente, el velo constante se perfora por completo. Depende completamente del diseñador de API asegurarse de que mutableno destruya el constconcepto y solo se use en casos especiales útiles. La mutablepalabra clave ayuda porque marca claramente los miembros de datos que están sujetos a estos casos especiales.

En la práctica, puedes utilizarlo constobsesivamente en todo tu código base (esencialmente quieres "infectar" tu código base con la const"enfermedad"). En este mundo, los punteros y las referencias, constcon muy pocas excepciones, producen un código que es más fácil de razonar y comprender. Para una digresión interesante, consulte "transparencia referencial".

Sin la mutablepalabra clave, eventualmente se verá obligado a utilizarla const_castpara 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 que mutableporque obliga al cliente API a destruir la constprotección de los objetos que está utilizando. Además, causa constuna destrucción generalizada: const_castla creación de un puntero o referencia constante permite acceso sin restricciones a la escritura y a las llamadas a métodos a los miembros visibles. Por el contrario, mutablerequiere que el diseñador de API ejerza un control detallado sobre las constexcepciones y, por lo general, estas excepciones están ocultas en constmétodos que operan con datos privados.

(NB: me refiero a la visibilidad de datos y métodos varias veces. Me refiero a miembros marcados como públicos versus privados o protegidos, que es un tipo totalmente diferente de protección de objetos que se analiza aquí ).

Dan L avatar Mar 05 '2010 02:03 Dan L

Su uso con boost::mutex es exactamente para lo que está destinada esta palabra clave. Otro uso es 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 visible externamente del objeto.

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

 avatar Sep 19 '2008 20:09