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)さえ引き起こしました。mutableを使用するか、設計を変更する必要がありました。