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_rep checks to see if there's a cached string representation of the date. If not, it calls the compute_cache_value method to create the string representation and cache it, and then marks the cache representation as valid so future calls to string_rep don't recalculate it.
The line const Date d2; will display undefined behavior because the compiler may assume it can put d2 in nonvolatile memory (e.g. flash in a microcontroller, or read-only-flagged memory or memory-mapped memory), and the const_cast<Date*> may not work in that case, resulting in cache_valid staying false or cache staying 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, the mutable keyword comes in handy. In short, marking a class member mutable tells the compiler that the member may be changed even if the object is const.
class Date
{
mutable bool cache_valid;
mutable string cache;
void compute_cache_value() const;
// ...
public:
// ...
string string_rep() const;
};
string Date::string_rep() const
{
if (cache_valid == false) {
compute_cache_value();
cache_valid = true;
}
return cache;
}
... though I'd argue that it's compute_cache_value's responsibility to set cache_valid, and I'd consider adding operator string() const { return string_rep(); } to Date.
One last thing that's neat about mutable is that the compiler has a better idea of what is going on, and in a case like d2, can put the object in volatile memory despite its declaration as const.
string_rep() returns a string representation of the cache data. The undefined behavior in example 4 comes about because of the explicit declaration of d2 as const. const_cast can only be used (with defined behavior) to cast away implicit const'ness.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With