Question

I had assumed that the canonical form for operator+, assuming the existence of an overloaded operator+= member function, was like this:

const T operator+(const T& lhs, const T& rhs)
{
    return T(lhs) +=rhs;
}

But it was pointed out to me that this would also work:

const T operator+ (T lhs, const T& rhs)
{
    return lhs+=rhs;
}

In essence, this form transfers creation of the temporary from the body of the implementation to the function call.

It seems a little awkward to have different types for the two parameters, but is there anything wrong with the second form? Is there a reason to prefer one over the other?

Was it helpful?

Solution

With the edited question, the first form would be preferred. The compiler will more likely optimize the return value (you could verify this by placing a breakpoint in the constructor for T). The first form also takes both parameters as const, which would be more desirable.

Research on the topic of return value optimization, such as this link as a quick example: http://www.cs.cmu.edu/~gilpin/c++/performance.html

OTHER TIPS

I'm not sure if there is much difference in the generated code for either.

Between these two, I would (personally) prefer the first form since it better conveys the intention. This is with respect to both your reuse of the += operator and the idiom of passing templatized types by const&.

I would prefer the first form for readability.

I had to think twice before I saw that the first parameter was being copied in. I was not expecting that. Therefore as both versions are probably just as efficient I would pick them one that is easier to read.

const T operator+(const T& lhs, const T& rhs)
{
    return T(lhs)+=rhs;
}

why not this if you want the terseness?

My first thought is that the second version might be infinitessimally faster than the first, because no reference is pushed on the stack as an argument. However, this would be very compiler-dependant, and depends for instance on whether the compiler performs Named Return Value Optimization or not.

Anyway, in case of any doubt, never choose for a very small performance gain that might not even exist and you more than likely won't need -- choose the clearest version, which is the first.

Actually, the second is preferred. As stated in the c++ standard,

3.7.2/2: Automatic storage duration

If a named automatic object has initialization or a destructor with side effects, it shall not be destroyed before the end of its block, nor shall it be eliminated as an optimization even if it appears to be unused, except that a class object or its copy may be eliminated as specified in 12.8.

That is, because an unnamed temporary object is created using a copy constructor, the compiler may not use the return value optimization. For the second case, however, the unnamed return value optimization is allowed. Note that if your compiler implements named return value optimization, the best code is

const T operator+(const T& lhs, const T& rhs)
{
    T temp(lhs);
    temp +=rhs;
    return temp;
}

I think that if you inlined them both (I would since they're just forwarding functions, and presumably the operator+=() function is out-of-line), you'd get near indistinguishable code generation. That said, the first is more canonical. The second version is needlessly "cute".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top