Some authors advocate returning const objects:
const Point operator+(const Point&, const Point&);
^^^^^
Returning a const object prevents some bad code from compiling:
Point a, b, c;
(a + b) = c; // error
But it also prevents some potentially convenient constructs:
Point a, b, c;
a = (b + c).normalize(); // error
The best argument I've heard to settle this standoff is that
returning const objects makes them behave like built-in types:
int x, y, z, w;
x = (y + z) *= w; // error
Are there any other compelling reasons to adopt/ignore this
convention?
My vote is to ignore this convention. Good conventions prevent
/accidental/ errors. When was the last time you saw something like this
happen by accident:
(a + b) = c; // error
?!
I've never seen it happen. Otoh, I have personally used constructs like:
a = (b + c).normalize();
and would be frustrated if the return of op+ forced me to make a useless
copy:
a = Point(b + c).normalize();
It would be more fun to just insert sleep cycles in my code. :-\
Looking at the evolution of C++, I believe we will see move semantics in
C++0X (I'm currently working very hard to make that happen). And const
return types will defeat the tremendous performance optimizations made
by move semantics.
Reference:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html
Consider:
std::vector<int>
foo(unsigned n)
{
return std::vector<int>(n);
}
int main()
{
std::vector<int> v;
v = foo(3);
}
Today this code will go to the heap at least twice:
1. To create the vector inside of foo.
2. To assign from foo's return to v.
On some compilers you may actually go to the heap 3 times (if RVO isn't
implemented).
If/when move semantics comes to a compiler near you, the above program
will go to the heap only once, whether or not RVO is implemented.
1. To create the vector inside of foo.
The assignment will be a "move assignment", transferring resources from
the temporary (foo's return) to v. Any copies that are not elided away
in the call to foo will use vector's move constructor instead of
vector's copy constructor.
However if you would like to completely disable this optimization which
move semantics will give you, simply code:
const std::vector<int>
foo(unsigned n)
{
return std::vector<int>(n);
}
More sleep cycles anyone? ;-)
Although you can't take advantage of move semantics today, I believe you
will in the future. Coding const return values today is just planting
silent performance killers in tomorrow's code.
-Howard