1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
Earlier, in section ref(ConstFunctions), the concepts of const member
functions and const objects were introduced.
bf(C++) also allows the declaration of data members which may be modified,
even by const member function. The declaration of such data members in the
class interface start with the keyword ti(mutable).
Mutable should be used for those data members that may be modified without
logically changing the object, which might therefore still be considered a
constant object.
An example of a situation where tt(mutable) is appropriately used is found in
the implementation of a string class. Consider the tt(std::string)'s tt(c_str)
and tt(data) members. The actual data returned by the two members are
identical, but tt(c_str) must ensure that the returned string is terminated by
an 0-byte. As a string object has both a length and a capacity an easy
way to implement tt(c_str) is to ensure that the string's capacity exceeds its
length by at least one character. This invariant allows tt(c_str) to be
implemented as follows:
verb(
char const *string::c_str() const
{
d_data[d_length] = 0;
return d_data;
}
)
This implementation logically does not modify the object's data as the
bytes beyond the object's initial (length) characters have undefined
values. But in order to use this implementation tt(d_data) must be declared
tt(mutable):
verb(
mutable char *d_data;
)
The keyword tt(mutable) is also useful in classes implementing, e.g.,
reference counting. Consider a class implementing reference counting for
textstrings. The object doing the reference counting might be a const object,
but the class may define a copy constructor. Since const objects can't be
modified, how would the copy constructor be able to increment the reference
count? Here the tt(mutable) keyword may profitably be used, as it can be
incremented and decremented, even though its object is a const object.
The keyword tt(mutable) should sparingly be used. Data modified by const
member functions should never logically modify the object, and it should be
easy to demonstrate this. As a i(rule of thumb): do not use tt(mutable)
unless there is a very clear reason (the object is logically not altered) for
violating this rule.
|