Última atualização:2026-10-12
A palavra-chave mutable em C++¶
Um mergulho profundo na palavra-chave mutable em C++¶
Em C++, a palavra-chave mutable é frequentemente vista como uma ferramenta para "atravessar" a restrição de constância (const). Em certas situações, embora queiramos impor proteção de constância a um objeto, ainda precisamos modificar alguns dos seus membros de dados. Este artigo explora em detalhes os cenários de uso de mutable e a filosofia de design por trás dele, e discute como ele resolve necessidades específicas de programação em C++.
1. Uso básico da palavra-chave mutable¶
Sabemos que, quando uma função membro é modificada por const, ela garante que não modificará o estado do objeto. Na prática, porém, às vezes queremos modificar um membro de dados e ainda assim manter a função membro marcada como const. É aqui que entra a palavra-chave mutable:
class Foo
{
private:
mutable bool done_;
public:
void doSomething() const {
// 在 const 成员函数中修改 mutable 成员
done_ = true;
}
};
No exemplo acima, doSomething() é declarada como const, indicando que ela não altera o estado do objeto. No entanto, done_ está marcado como mutable, o que significa que podemos modificar done_ mesmo dentro de um método const. Esse design permite gerenciar certos dados que precisam ser modificados mantendo inalterada a semântica da interface da função.
2. Constância lógica vs. constância de bits¶
A constância em C++ pode ser dividida em dois tipos: constância lógica e constância de bits. A constância lógica significa que o estado do objeto, visto de fora, não mudou; a constância de bits significa que os bits do objeto na memória permanecem inalterados. A palavra-chave mutable nos permite definir a constância lógica, ou seja, mesmo que alguns dados internos do objeto mudem, o estado do objeto, em termos lógicos, não sofre alteração visível.
Por exemplo, em uma classe thread-safe, podemos usar boost::mutex para proteger o acesso aos dados. Para adquirir o bloqueio dentro de um método const, podemos declarar o 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_;
}
};
No exemplo acima, embora o método getData seja declarado const, precisamos do bloqueio para garantir a segurança de threads no acesso aos dados. Por isso, declaramos mtx_ como mutable, permitindo modificá-lo dentro de um método const. Nesse caso, dizemos que o estado lógico da classe não mudou; a modificação serve apenas para garantir a segurança de threads.
3. mutable em expressões Lambda¶
A partir do C++11, mutable também pode ser usado em expressões lambda para permitir a modificação de variáveis capturadas por valor. Por padrão, as variáveis capturadas por valor em uma lambda são imutáveis. Se for necessário modificar a variável capturada dentro da lambda, pode-se usar mutable:
int x = 0;
auto f1 = [=]() mutable { x = 42; }; // OK: 可以修改捕获的 x
auto f2 = [=]() { x = 42; }; // Error: 按值捕获的变量不能被修改
Nesse caso, mutable nos permite modificar a variável capturada dentro do corpo da função sem afetar o valor da variável externa.
4. Evitar o uso de const_cast¶
Sem a palavra-chave mutable, talvez precisássemos usar const_cast para tratar esses casos especiais. O const_cast remove a constância do objeto, mas tem desvantagens: ele pode eliminar completamente a proteção de constância, permitindo modificações e chamadas de métodos arbitrárias sobre o objeto, o que reduz a legibilidade e a segurança do código.
Em comparação, a palavra-chave mutable oferece um controle mais refinado. Com mutable, podemos criar "exceções" em membros de dados específicos, permitindo sua modificação em métodos const, sem remover a constância do objeto inteiro. Por isso, mutable trata esses casos especiais com mais segurança.
5. A filosofia de design do uso de mutable¶
A filosofia de design da palavra-chave mutable está em preservar a constância lógica da interface. Na maioria dos casos, queremos escrever código const-correct, o que significa que o estado do objeto não muda sem uma modificação explícita. mutable nos permite fazer concessões em certas implementações internas — como caches, contagem de referências, informações de depuração, etc. — sem quebrar a consistência desse design de interface.
Ao projetar uma interface, devemos deixar claro quando e por que o estado de um objeto precisa ser modificado. A palavra-chave mutable permite que o código permaneça inalterado no nível lógico e, ao mesmo tempo, oferece a capacidade de modificar membros de dados específicos. Isso exige reflexão por parte do projetista, garantindo que o uso de mutable não corrompa o conceito de constância do objeto, usando-o somente quando realmente necessário.
6.Referências¶
Tópicos relacionados¶
- Funções virtuais puras e classes abstratas em C++ | C++那些事
- Asserções com assert em C++ | C++那些事
- Bit fields em C++ | C++那些事
- Implementando polimorfismo de C++ em linguagem C | C++那些事
- Constantes e modificadores com const em C++ | C++那些事
- A família completa do const em C++ | C++那些事
- O operador de desreferência * em C++ | C++那些事
- Inicialização e atribuição em C++ | C++那些事
- Formas de retornar múltiplos valores em C++ | C++那些事
- C++ restrict e otimização do compilador | C++那些事