FAQ 14.12 How can a "nonobservable" data member be updated within a const member function?
A small percentage of inspectors need to make nonobservable changes to data members. For example, an object whose storage is physically located in a database might want to cache its last lookup in hopes of improving the performance of its next lookup. In this case there are two critical issues: (1) if someone changes the database, the cached value must somehow be either changed or marked as invalid (cache coherency); (2) the const lookup member function needs to make a change to the cached value. In cases like this, changes to the cache are not observable to users of the object (the object does not change its abstract state; see FAQ 14.09). The easiest way to implement a nonobservable change is to declare the cache using the mutable keyword. The mutable keyword tells the compiler that const member functions are allowed to change the data member. int readFromDatabase() throw() { return 42; } <-- 1 class Fred { public: int get() const throw(); private: mutable int cache_; mutable bool cacheOk_; }; int Fred::get() const throw() { if (! cacheOk_) { cache_ = readFromDatabase(); cacheOk_ = true; } return cache_; } int main() { Fred f; int x = f.get(); <-- 2 int y = f.get(); <-- 3 int z = f.get(); <-- 4 }
The second alternative is to cast away the constness of the this pointer using the const_cast keyword. In the following example, self is equal to this (that is, they point to the same object), but self is a Fred* rather than a const Fred* so self can be used to modify the this object. class Fred2 { public: int get() const throw(); private: int cache_; bool cacheOk_; }; int Fred2::get() const throw() { if (! cacheOk_) { Fred2* self = const_cast<Fred2*>(this); self->cache_ = readFromDatabase(); self->cacheOk_ = true; } return cache_; } |