Last week I asked you to please make member functions const
whenever possible. But constant doesn’t always mean constant.
Declaring an object const
is a way to tell the compiler that this object cannot be changed whatsoever. What you actually try to express might however be a logical immutability, that the meaning of the object should not change. That doesn’t necessarily imply that none of its member variables can be changed.
The most common example is to cache the result of an expensive operation. To expand on last weeks example:
class Whisky { public: Smell smellIt() const; Taste tasteIt(int ml); };
Imagine that computing the smell of the whisky is a complicated operation [1], that you don’t want to do every time someone smells it. You might want to introduce a private member to hold a cached description of the smell. This member must be possible to change, to be able to write the cached value. Computing and storing this value does however not logically modify the object, so it should be possible to do even for const
objects. To allow for this, use the mutable
keyword:
class Whisky { public: Smell smellIt() const; Taste tasteIt(int ml); private: mutable Smell* smell; };
The definition of smellIt() would now look something like this:
Smell Whisky::smellIt() const { if (!smell) smell = computeSmell(); //Assume this function exists and returns a new, dynamically allocated Smell object return *smell; }
Exactly how you do the caching is up to you, but if you use a simple pointer (and not for instance a shared_ptr
), you must remember to delete smell
in ~Whisky()
.