Item 3: Use const whenever possible
file:///C|/Users/Administrator/Desktop/EffectiveC++/0321334876/ch01lev1sec3.html[2015/2/10 15:26:41]
Also note that the return type of the non-const operator[] is a reference to a char — a char itself would not do. If operator[] did return a
simple
char, statements like this wouldn't compile:
tb[0] = 'x';
That's because it's never legal to modify the return value of a function that returns a built-in type. Even if it were legal, the fact that C++ returns
objects by value (see Item 20) would mean that a copy of
tb.text[0] would be modified, not tb.text[0] itself, and that's not the behavior you
want.
Let's take a brief time-out for philosophy. What does it mean for a member function to be
const? There are two prevailing notions: bitwise
constness (also known as physical constness) and logical constness.
The bitwise
const camp believes that a member function is const if and only if it doesn't modify any of the object's data members (excluding those
that are static), i.e., if it doesn't modify any of the bits inside the object. The nice thing about bitwise constness is that it's easy to detect violations:
compilers just look for assignments to data members. In fact, bitwise constness is C++'s definition of constness, and a
const member function isn't
allowed to modify any of the non-static data members of the object on which it is invoked.
Unfortunately, many member functions that don't act very
const pass the bitwise test. In particular, a member function that modifies what a pointer
points to frequently doesn't act
const. But if only the pointer is in the object, the function is bitwise const, and compilers won't complain. That
can lead to counterintuitive behavior. For example, suppose we have a
TextBlock-like class that stores its data as a char* instead of a string,
because it needs to communicate through a C API that doesn't understand
string objects.
class CTextBlock {
public:
...
char& operator[](std::size_t position) const // inappropriate (but bitwise
{ return pText[position]; } // const) declaration of
// operator[]
private:
char *pText;
};
This class (inappropriately) declares operator[] as a const member function, even though that function returns a reference to the object's internal
data (a topic treated in depth in Item 28). Set that aside and note that
operator[]'s implementation doesn't modify pText in any way. As a result,
compilers will happily generate code for
operator[]; it is, after all, bitwise const, and that's all compilers check for. But look what it allows to
happen:
const CTextBlock cctb("Hello"); // declare constant object
char *pc = &cctb[0]; // call the const operator[] to get a
// pointer to cctb's data
*pc = 'J'; // cctb now has the value "Jello"
Surely there is something wrong when you create a constant object with a particular value and you invoke only const member functions on it, yet
you still change its value!
This leads to the notion of logical constness. Adherents to this philosophy argue that a
const member function might modify some of the bits in the
object on which it's invoked, but only in ways that clients cannot detect. For example, your
CTextBlock class might want to cache the length of the
textblock whenever it's requested:
class CTextBlock {