mutable în C++

Permite modificarea unui membru chiar și în metode const sau modificarea variabilelor capturate prin copie într-o lambda.

Sintaxă
mutable int contor;           // membru modificabil și în metode const
[x]() mutable { ++x; }        // lambda care își poate modifica copiile

Ce face mutable

O metodă const nu poate modifica membrii obiectului. Uneori însă un membru nu face parte din „starea vizibilă” a obiectului: un contor de accesări, un rezultat salvat (cache), un std::mutex. Marcat mutable, un astfel de membru poate fi modificat și în metodele const.

La lambda, variabilele capturate prin copie ([x]) sunt implicit constante în corpul lambdei. Cu mutable, lambda își poate modifica propria copie; variabila originală rămâne neschimbată.

Exemple

Exemplul 1: Contor de accesări într-o metodă const

#include <print>
#include <string>
#include <utility>

class Articol {
public:
    explicit Articol(std::string titlu) : titlu_(std::move(titlu)) {}
    const std::string& titlu() const {
        ++citiri_;  // permis, pentru că citiri_ este mutable
        return titlu_;
    }
    int citiri() const { return citiri_; }
private:
    std::string titlu_;
    mutable int citiri_ = 0;
};

int main() {
    const Articol a("Învață C++");
    std::println("{}", a.titlu());
    std::println("{}", a.titlu());
    std::println("Citit de {} ori", a.citiri());
}

Rezultat

Învață C++
Învață C++
Citit de 2 ori

Exemplul 2: Lambda mutable

Lambda are propria copie a lui numar și o crește la fiecare apel. Variabila din main rămâne 0.

#include <print>

int main() {
    int numar = 0;
    auto urmatorul = [numar]() mutable { return ++numar; };
    std::println("{} {} {}", urmatorul(), urmatorul(), urmatorul());
    std::println("numar în main: {}", numar);
}

Rezultat

1 2 3
numar în main: 0

Greșeli frecvente

  • Marchezi mutable membri care țin starea reală a obiectului doar ca să scapi de erorile de const. Promisiunea „metoda nu schimbă obiectul” devine falsă.
  • Te aștepți ca o lambda mutable cu captură prin copie să modifice variabila originală. Pentru asta capturează prin referință: [&numar].

Comenzi înrudite

  • const: Marchează o valoare care nu mai poate fi modificată după inițializare; compilatorul oprește orice încercare de schimbare.
  • lambda ([](){}): O funcție fără nume, scrisă direct acolo unde e folosită; poate „captura” variabile din jur.
  • class: Definește un tip nou care grupează date (membri) și funcțiile care lucrează cu ele (metode); baza programării orientate pe obiecte.