4

For example, in the OGRE3D engine, I often see things like

class_name class_name :: operator + (class_name & object)

Instead of

class_name class_name :: operator + (class_name object)

Well it's not that I prefer the second form, but is there a particular reason to use a reference in the input ? Does it has special cases where it is necessary to use a reference instead of a copy-by-value ? Or is a performance matter ?

jokoon
  • 6,207
  • 11
  • 48
  • 85
  • 2
    There are other good answers already, but I'd like to add that passing a `const class_name&` is usually preferred to passing a `class_name` for all functions, not just overloaded operators. – aschepler Oct 21 '10 at 15:40
  • @aschepler: it's the same "optimization" that can be done with `operator=` overloads. Pass by value and you get your temporary (without copy), implementation is then `return object += *this;`. Of course, whether or not this actually is faster is another topic :) – Matthieu M. Oct 21 '10 at 17:20

5 Answers5

4

It's a performance issue. Passing by reference will generally be cheaper than passing by value (it's basically equivalent to passing by pointer).

On an unrelated note, you probably want the argument to operator+ to be const class_name &object.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 2
    +1, the actual signature should be closer to `type type::operator+( type const & ) const` (note the two `const` s) or better yet `type operator+( type lhs, type const & rhs ) { return lhs += rhs; }` as a free function (first argument by value, second by const reference) – David Rodríguez - dribeas Oct 21 '10 at 15:45
  • 1
    @Inverse: Yes, that's why I say "generally". – Oliver Charlesworth Oct 21 '10 at 16:12
  • Super old thread, but I found it on google so thought I should add some info: Return type should be const class_name, otherwise you can compile the following code: (a+b)=c; Which is clearly silly in almost all cases. –  Aug 21 '14 at 05:28
3

It is recommended to implement operator+ in terms of operator+=. First make a copy of the left argument, then modify it, and finally return the copy. Since you are going to copy the left argument anyway, you might just as well do it by using call by value for the left argument:

class_name operator+(class_name x, const class_name& y)
{
    return x += y;
}

In C++0x, you should enable move semantics for the result:

#include <utility>

class_name operator+(class_name x, const class_name& y)
{
    return std::move(x += y);
}
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
2

Besides the "usual" calling conventions for regular methods, I would note that the operators are somewhat peculiar.

The main reason to use const& instead of pass-by-value is correctness (performance comes second, at least in my mind). If your value may be polymorphic, then a copy means object slicing, which is undefined behavior in general.

Therefore, if you use pass-by-value, you clearly state to your caller that the object will be copied and it should not be polymorphic.

Another reason can be performance. If the class is small and its copy-constructor trivial, it might be faster to copy it than to use indirection (think of an int-like class). There are other cases where pass-by-value can be faster, but in non-inline cases they are rarer.

I do think however that none of these is the real reason and the developers just picked this out of the blue...

... because the real WTF (as they say) is that the operator@ should be declared as free functions to allow argument promotion of the left-hand side argument ...

So if they didn't follow this rule, why would they bother with usual argument passing style ?

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • "... because the real WTF (as they say) is that the operator@ should be declared as free functions to allow argument promotion of the left-hand side argument ..." : can you be more specific ? I don't know what you are talking about and I don't find anything about it... – jokoon Oct 23 '10 at 09:47
  • @gokoon: sorry for the late reply. Say you have a `Number` class and you define `Number Number::operator+(int) const`. Then `Number n(5); Number q = n + 4;` is correct but `Number r = 4 + n;` will not compile, because there is no `operator+` that takes `(int,Number)` as parameters. However, if you define `Number operator+(Number, int)`, `Number operator+(int, Number)` and `Number operator+(Number, Number)` then you can use any combination of `Number` and `int` as argument. – Matthieu M. Nov 04 '10 at 08:52
  • @gokoon: ... Also, *argument promotion* refers to transforming an argument `int` to `Number` for example, which is not possible on the left hand side argument in case of a class-method. – Matthieu M. Nov 04 '10 at 08:53
  • @gokoon: sorry about that, `operator@` is often used as a placeholder for any function beginning by `operator` like `operator+`, `operator-`, `operator*` when one is talking about a behavior that applies generally to all of them. – Matthieu M. Nov 04 '10 at 10:42
1

So that object doesn't get copied from the original parameter. In fact, the preferred way is to pass object as const, and to make operator+ as const member operator:

class_name class_name :: operator + (const class_name& object) const;
Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
-1

Passing a reference is much faster than copying the whole instance of your class of course. Also, if there is no copy constructor defined for the class, it could be dangerous to copy it (default copy constructor will just copy pointers and the destructor will delete them for example).

When passing classes to a method or operator, the best is to always pass a reference. You can declare it const to be sure it is not modified to avoid side effects.

Benoit Thiery
  • 6,325
  • 4
  • 22
  • 28