const informuje kompilator, że zmienna jest niezmienna (nie może być zmieniana po inicjalizacji). Używane jest do zadeklarowania zmiennych stałych, a także do metod, które gwarantują, że nie zmieniają stanu obiektu.
mutable pozwala na zmianę wartości pola klasy nawet wewnątrz metod const.
volatile informuje kompilator, że wartość zmiennej może być zmieniana gdzieś poza kontrolą programu (np. przez sprzęt) i kompilator nie powinien optymalizować dostępu do niej.
class Logger { public: void log() const { ++count; // Dozwolone — count zadeklarowany jako mutable } private: mutable int count = 0; }; volatile int flag; void wait() { while (flag == 0) { /* kompilator nie optymalizuje pętli, ponieważ flag jest volatile */ } }
„Co się stanie, jeśli zadeklarujesz członka klasy jednocześnie jako
constimutable?”
Odpowiedź: Nie można tego zrobić, to wykluczające się kwalifikatory; kompilator zgłosi błąd.
Historia
W oprogramowaniu przemysłowym do pracy ze sprzętem programista zadeklarował dane, aktualizowane przez zewnętrzne przerwania, jako zwykłe int. Optymalizacja kompilatora usunęła powtarzające się odczyty tych zmiennych, przez co program "zawiesił się" w nieskończonej pętli. Problem udało się zdiagnozować dopiero po zamianie na
volatile int.
Historia
Jedna z klas logowania miała metodę
log() const, w której należało aktualizować licznik wywołań. Na początku robiono to przez wskaźnikconst_cast, co spowodowało wiele ostrzeżeń i nieoczywistych błędów. Problem zniknął po prawidłowym zadeklarowaniu licznika jakomutable.
Historia
Niektóre metody klasy były zadeklarowane jako
const, ale człony typu wskaźnika zmieniały się (np. w celu realizacji buforowania). To prowadziło do naruszenia logiki „const-correctness” i nawet UB, jeśli obiekt rzeczywiście znajdował się w obszarze tylko do odczytu. N należało używaćmutablelub zmienić projekt.