tags:
- Cpp
Mutable and The M&M Rule in C++ (ENG)
Do this at first: Const in C++
The mutable
specifier allows a member to be modified in a const
member function. In the example below, we qualify a function with const
, which means we are not supposed to change the class members in the function. However, we do modify the mutable count
member within the function scope.
class myClass{
private:
int variable = 0;
mutable int count;
public:
int getVar() const{
count++;
return variable;
}
};
int main(){
myClass obj;
int value = obj.getVar();
return 0;
}
"Const as a promise", using mutable
specifier can break the constness of a function, which can be seen as poor code design. The principal of "const as a promise" implies that a const
member function should not modify any member variables. But mutable
is an exception to this rule, which can lead to unexcepted behavior.
However, mutable
could be useful in some situations like mutexes for safer code(the M&M rule), cache memory, and lazy evaluation.
This code example is copied from cppreference. As you can see, we have a const
get()
function, and with std::mutex
, we create safe concurrent code. Why is that? While we are not supposed to modify anything in the const
specified functions, with mutable
, another thread can actually modify the data in a const
specified function. This is no thread-safe.
class ThreadsafeCounter
{
mutable std::mutex m; // The "M&M rule": mutable and mutex go together
int data = 0;
public:
int get() const
{
std::lock_guard<std::mutex> lk(m);
return data;
}
void inc()
{
std::lock_guard<std::mutex> lk(m);
++data;
}
};
For achieving the goal of safer code and const correctness at the same time, we have to use the mutable
keyword to make the mutex mutable in the const
function. While a thread is modifying the critical section, using a lock to prevent other threads from entering and accessing the resource is thus necessary.