Última actualización:2026-10-12
La palabra clave mutable en C++¶
Un vistazo en profundidad a la palabra clave mutable en C++¶
En C++, la palabra clave mutable suele considerarse la herramienta para “atravesar” la limitación de constancia (const). En ciertos casos, aunque queremos imponer protección de constancia a un objeto, todavía necesitamos modificar algunos de sus miembros de datos. Este artículo explora en detalle los escenarios de uso de mutable y la filosofía de diseño que hay detrás, y analiza cómo resuelve en C++ necesidades de programación concretas.
1. Uso básico de la palabra clave mutable¶
Sabemos que cuando una función miembro está calificada con const, esa función miembro garantiza que no modificará el estado del objeto. Sin embargo, en la práctica, a veces queremos modificar un miembro de datos y aun así marcar la función miembro como const. Esa es la función de la palabra clave mutable:
class Foo
{
private:
mutable bool done_;
public:
void doSomething() const {
// 在 const 成员函数中修改 mutable 成员
done_ = true;
}
};
doSomething() está declarada como const, lo que indica que no cambiará el estado del objeto. Sin embargo, done_ está marcado como mutable, lo que significa que incluso en un método const podemos modificar done_. Este diseño permite gestionar ciertos datos que necesitan modificarse manteniendo invariante la semántica de la interfaz de la función.
2. Constancia lógica frente a constancia a nivel de bits¶
La constancia en C++ puede dividirse en dos categorías: constancia lógica y constancia a nivel de bits. La constancia lógica significa que el estado del objeto no muestra cambios desde el exterior, mientras que la constancia a nivel de bits significa que los bits del objeto en memoria se mantienen sin cambios. La palabra clave mutable nos permite definir la constancia lógica: aunque algunos datos internos del objeto cambien, lógicamente el estado del objeto no sufre ningún cambio visible.
Por ejemplo, en una clase segura para hilos podemos usar boost::mutex para proteger el acceso a los datos. Para adquirir el bloqueo en un método const, podemos declarar el mutex como mutable:
class ThreadSafeClass {
private:
mutable std::mutex mtx_;
int data_;
public:
int getData() const {
std::lock_guard<std::mutex> lock(mtx_);
return data_;
}
};
getData está declarado como const, necesitamos un bloqueo para garantizar la seguridad de hilos del acceso a los datos. Por eso declaramos mtx_ como mutable, para permitir su modificación en un método const. En este caso decimos que el estado lógico de la clase no ha cambiado; la modificación solo se hace para garantizar la seguridad de los hilos.
3. mutable en expresiones lambda¶
Desde C++11, mutable también puede usarse en expresiones lambda para permitir modificar las variables capturadas por valor. Por defecto, las variables capturadas por valor en una lambda son inmutables. Si necesitas modificar dentro de la lambda una variable capturada, puedes usar mutable:
int x = 0;
auto f1 = [=]() mutable { x = 42; }; // OK: 可以修改捕获的 x
auto f2 = [=]() { x = 42; }; // Error: 按值捕获的变量不能被修改
mutable nos permite modificar dentro del cuerpo de la función la variable capturada sin afectar al valor de la variable externa.
4. Evitar el uso de const_cast¶
Sin la palabra clave mutable, quizá tengamos que usar const_cast para manejar estos casos especiales. const_cast puede eliminar la constancia de un objeto, pero tiene inconvenientes: const_cast puede eliminar por completo la protección de constancia, permitiéndonos hacer modificaciones y llamadas a métodos arbitrarias sobre el objeto, lo que reduce la legibilidad y la seguridad del código.
En comparación, la palabra clave mutable ofrece un control más fino. Con mutable podemos establecer “excepciones” en miembros de datos concretos, permitiendo su modificación en métodos const, sin tener que eliminar la constancia de todo el objeto. Por eso mutable permite manejar estos casos especiales de forma más segura.
5. Filosofía de diseño del uso de mutable¶
La filosofía de diseño de la palabra clave mutable consiste en preservar la constancia lógica de la interfaz. En la mayoría de los casos queremos escribir código const-correct, lo que significa que el estado del objeto no cambia si no se modifica explícitamente. mutable nos permite hacer concesiones en ciertos detalles internos de la implementación, como la caché, el conteo de referencias o la información de depuración, sin romper la coherencia de ese diseño de interfaz.
Al diseñar una interfaz, debemos tener claro cuándo y por qué hay que modificar el estado de un objeto. La palabra clave mutable permite que el código permanezca invariante en el plano lógico y a la vez da la capacidad de modificar miembros de datos concretos. Esto exige una reflexión cuidadosa por parte de quien diseña, asegurándose de que el uso de mutable no destruya el concepto de constancia del objeto, y utilizándolo solo cuando sea realmente necesario.
6. Referencias¶
Temas relacionados¶
- Funciones virtuales puras y clases abstractas en C++ | C++那些事
- Aserciones assert en C++ | C++那些事
- Campos de bits en C++ | C++那些事
- Implementar el polimorfismo de C++ en lenguaje C | C++那些事
- const en C++: constantes y modificación | C++那些事
- La familia completa de const en C++ | C++那些事
- El operador de desreferencia * en C++ | C++那些事
- Inicialización y asignación en C++ | C++那些事
- Formas de devolver varios valores en C++ | C++那些事
- C++ restrict y optimización del compilador | C++那些事