In the book of “The C++ programming language”, author gave the following example. He mentioned that ” the cache needs to be filled before it can be used”. It seems to me that this is why the function of compute_cache_value is placed. But I do not understand what does the function of string_rep( ) do in accordance with its implementation. Thanks for clarification.
class Date{
bool cache_valid;
string cache;
void compute_cache_value( ); //fill cache
// ...
public:
// ...
string string_rep( ) const;
};
string Date:: string_rep( ) const
{
if (cache_valid == false) {
Date* th = const_cast<Date*> (this); // cast away const
th->compute_cache_value( );
th->cache_valid = true;
}
return cache;
}
In addition, the author gave the following for examples:
Date d1;
const Date d2;
string s1 = d1.string_rep( );
string s2 = d2.string_rep( );
And the author stated that the fourth example will display undefined behavior. I would like to know why.
string_repchecks to see if there’s a cached string representation of the date. If not, it calls thecompute_cache_valuemethod to create the string representation and cache it, and then marks the cache representation as valid so future calls tostring_repdon’t recalculate it.The line
const Date d2;will display undefined behavior because the compiler may assume it can putd2in nonvolatile memory (e.g. flash in a microcontroller, or read-only-flagged memory or memory-mapped memory), and theconst_cast<Date*>may not work in that case, resulting incache_validstayingfalseorcachestaying as an empty string.P.S. As Michael J below points out below, there are almost always better ways to do things than using
const_cast. In the case of this example, themutablekeyword comes in handy. In short, marking a class membermutabletells the compiler that the member may be changed even if the object isconst.… though I’d argue that it’s
compute_cache_value‘s responsibility to setcache_valid, and I’d consider addingoperator string() const { return string_rep(); }toDate.One last thing that’s neat about
mutableis that the compiler has a better idea of what is going on, and in a case liked2, can put the object in volatile memory despite its declaration asconst.