C++ Conceptual Constness
Introduction
In modern C++, conceptual constness becomes more important than bitwise constness. With the mutable
specifier, we could now create implementations that is consist with the interface with conceptual constness.
In this blog post, I would like to briefly discuss bitwise constness, conceptual constness, and the C++ mutable
specifier.
Bitwise Constness
Bitwise constness means none of the memory inside the object is modified inside the function. In C++, every object declared with const
achieves bitwise constness. It can usually be easily enforced because any operation that tries to modify the const
object will be prevented by the compiler.
1 | template <class T1, class T2> |
Conceptual Constness
Conceptual constness means the object’s abstract state isn’t modified inside the function, although its bits might be.
For example, if we want to create a thread-safe counter without using std::atomic
, the counter could be implemented as follows.
1 |
|
1 | $ g++ counter.cpp -o counter -lpthread -std=c++11 |
However, we found the ThreadSafeCounter::get
method look weird at the interface level because it is not a const
member function. Why would we ever want to modify the object if we just want to know its count? If it were a single thread counter, definitely we will make the get
method const
. Adding const
to the ThreadSafeCounter::get
method will not work because locking the mutex
will change the state of the object and the bitwise constness enforced by the compiler will prevent it.
The C++ mutable
specifier comes to save the conceptual constness in this scenario. mutable
permits modification of the class member declared mutable even if the containing object is declared const. By adding a mutable
specifier to the mutex
member variable, the const
get
method is allowed.
1 | class ThreadSafeCounter |
In addition to mutex
, the mutable
specifier is often used for the member cache variables in the object. After all, the cache should not affect the object conceptual constness.
Conclusions
Use mutable
wisely for conceptual constness and its corresponding interface. In C++ const
member functions implies that the member function is thread-safe and it can be called without synchronization. Conceptual constness extended bitwise constness, so the user should be more careful implementing the const
member functions in a thread-safe fashion.
C++ Conceptual Constness