“Physical” constness comes from declaring an object
const, and could, in principle, be enforced by placing the object in read-only memory, so it cannot change. Attempting to change it will cause undefined behaviour; it might change, or it might not, or it might trigger a protection fault, or it might melt the memory chip.
“Logical” constness comes from declaring a reference or pointer
const, and is enforced by the compiler. The object itself may or may not be “physically” const, but the reference cannot be used to modify it without a cast. If the object is not “physically” const, then C++ allows you to modify it, using
const_cast to circumvent the protection.
mutable class member can be modified even if the class object itself (or the reference or pointer used to access it) is
const. Examples of good uses of this are a mutex that must be locked during a read operation, and a cache to store the result of an expensive read operation. In both cases, the operation itself should be a
const function (since it doesn’t affect the visible state of the object), but it needs to modify the mutex or the cache, so these need to be
mutable. It can also be abused to make the object visibly change when logically it shouldn’t, so use it with care; only declare members
mutable if they don’t form part of the externally visible state.