“Effective C++” : Part 6

It’s time for another in the series of posts on effective C++. The nice part of these posts is that writing about the points forces me to learn about them and understand them well enough to summarize them for others.

20: Prefer pass-by-reference-to-const to pass-by-value: By default C++ passes objects to and from functions by value (Inherited functionality from C). Passing by value in C++ means that the constructor for the object passed and every base constructor will be called to create the new object that holds the value. If there are variables like strings in any of the objects their constructors will be called as well. The example in Scott’s book describes a class that extends two other classes. In this case there are several strings that results in six constructors and six destructors being called.

One of the advantages of passing by value is the peace of mind that the primary class cannot be altered. We can achieve the same behaviour by passing the object by reference to a constant. In this case no constructors or destructors are called and the object cannot be modified.

There is one other problem that will be discussed in points 34 and 36 called slicing that pass-by-reference-to-const avoids. I’ll leave the description of the problem for when those points are discussed.

It should be noted that this rules does not apply to built in types and STL iterator and function object types. The implementers of these types were responsible for making sure that they would be efficient to copy and that they would not suffer from the slicing problem.

21: Don’t try to return a reference when you must return an object: This rule can be linked to rule 20 in that once developers get the meaning of rule 20 they can get carried away and try to pass everything by reference. This eventually leads to a situation where the designer passes a reference to an object that doesn’t exist. There are a number of good yet convoluted examples in the book, but the bottom line is never return a pointer or reference to a local stack object, a reference to a hep-allocated object or a pointer or reference to a local static object, if there is a chance that more than one object such object will be needed.

The one example that stood out for me was:

const Rational& operator*(const Rational& ihs,
const Rational& rhs){
Rational result(ihs.n * rhs.n, lhs.d * rhs.d);
return result;
}

It the case above the function returns a reference to result which is a local variable which ceases to exist one you return from the function. If the calling routine tries to use the result, you get a one way ticket to “undefined behaviour”.

This entry was posted in General and tagged , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *