const сообщает компилятору, что переменная неизменяема (не может быть изменена после инициализации). Используется для объявления константных переменных, а также для методов, которые гарантированно не меняют состояние объекта.
mutable позволяет изменять значение поля класса даже внутри const-методов.
volatile сообщает компилятору, что значение переменной может быть изменено где-то вне контроля программы (например, оборудованием), и компилятор не должен оптимизировать обращения к ней.
class Logger { public: void log() const { ++count; // Допустимо — count объявлен mutable } private: mutable int count = 0; }; volatile int flag; void wait() { while (flag == 0) { /* компилятор не оптимизирует цикл, т.к. flag volatile */ } }
«Что будет, если объявить член класса одновременно как
constиmutable?»
Ответ: Так сделать нельзя, это взаимоисключающие квалификаторы; компилятор выдаст ошибку.
История
В промышленном ПО для работы с аппаратурой разработчик объявил данные, обновляемые внешними прерываниями, как обычные int. Оптимизация компилятора убрала повторяющиеся чтения этих переменных, из-за чего программа "зависла" в бесконечном цикле. Проблему удалось диагностировать только после замены на
volatile int.
История
Один из классов логирования имел метод
log() const, где требовалось обновлять счётчик вызовов. Поначалу это делали через указательconst_cast, что вызвало множество предупреждений и неочевидных багов. Проблема исчезла после правильного объявления счётчика черезmutable.
История
Некоторые методы класса были объявлены как
const, но члены типа указателя меняли (например, для реализации кэширования). Это приводило к нарушению логики "const-correctness" и даже UB, если объект реально размещался в read-only области. Следовало использоватьmutableили изменять дизайн.