7

Some time ago I was told, that the usual pattern to implement two-ary operators needs a final move in the return.

Matrix operator+(const Matrix &a, Matrix &&b) {
    b += a;
    return std::move(b);
}

But now there is the special rule that in a return the compiler may treat the return value as a temporary, and then this would not be necessary -- a simple return b would suffice.

But then again, b has a name in this function, therefore, its an LValue -- which hinders the compiler to m consider it being a temp, and the move is required.

Is this still the case in the most recent version of the C++0x Standard? We need the move to implement the above pattern?

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
towi
  • 21,587
  • 28
  • 106
  • 187
  • 2
    According to [this answer](http://stackoverflow.com/questions/6009004/are-value-parameters-implicitly-moved-when-returned-by-value/6009012#6009012), the `std::move` is not necessary. – fredoverflow Aug 21 '11 at 19:45
  • 2
    Although it could make a difference that the parameter is a `Matrix&&` instead of a `Matrix`... – fredoverflow Aug 21 '11 at 19:57
  • 2
    It *is* complicated, yes. And yes, I think you are right. If its a *value parameter* like `Matrix` then you have a pristine copy for you alone -- a temp. The compiler knows that you can grab from it. With `Matrix&&` I am not *that* sure- – towi Aug 21 '11 at 20:06

2 Answers2

7

You need the explicit std::move in this example because b is not the name of a non-volatile automatic object. Reference 12.8 [class.copy] /p31/b1:

  • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv- unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 2
    Ah, and references aren't objects. I think you should emphasize "object" instead of "automatic" (or both). – fredoverflow Aug 21 '11 at 20:09
  • I think **automatic** is the right \em here, because it translates (roughly? exactly?) to "local variable". – towi Aug 21 '11 at 20:22
0

I'm not sure why this function returns by value. Shouldn't this function return a Matrix&& like the following?

Matrix&& operator+(const Matrix &a, Matrix &&b) {
  b += a;
  return std::move(b);
}

This has the added advantage that x1 + x2 + x3 + ... + xn creates at most one temporary, which is important if Matrix happens to be stack allocated (as it then gains nothing from moves).

I think the signatures should be like the following:

Matrix&& operator+(Matrix &&a,      Matrix &&b     );
Matrix&& operator+(const Matrix &a, Matrix &&b     );
Matrix&& operator+(Matrix &&a,      const Matrix &b);
Matrix   operator+(const Matrix &a, const Matrix &b);
Clinton
  • 22,361
  • 15
  • 67
  • 163
  • No. You should not return a `&&`. This would mean, that you return a reference to one of the arguments, where you do not have the control of where it is coming from ("dont pick up whats lying on the street"). If you return a `Matrix` you can just `move` in the content from one of the arguments and you accomplish the same effect with perfect performance. Also, you dont need to overload on `(&&, &&)`: The code you would write there would be the same as in either `(&,&&)` or `(&&,&&)`. If you spare the `(&&,&&)` overload, one of those will be selected by the compiler. You need only 3 overloads. – towi Aug 23 '11 at 05:17
  • towi: What's wrong with returning a reference to one of the arguments? I thought only returning a reference to a temporary was an issue. – Clinton Aug 23 '11 at 05:46
  • 1
    @towi: Also, what evidence have you got that the `(&&, &&)` overload is not needed? I believe http://ideone.com/qf3Rn shows that it is needed. – Clinton Aug 23 '11 at 06:17
  • You are right, I think. It *is* correct, that a `&&` can bind to a `&` parameter, if there is no overload (there are of course many places which this is needed). But I missed, that, if you provide the overloads `(&,&&)` and `(&&,&)` for your/our example the compiler can not decide which one is better. I But it would be nice if there would be a "better" solution that adding an overload here, just to "deconfuse" the compiler. Feel free to edit here http://ideone.com/9ZhO3 – towi Aug 24 '11 at 08:58
  • No, you can also create issues returning a reference from an argument. Consider (modulo some `const`s) `Value& get(map &d, Value &dfault) { if(not-found) return dfault;}`. And then use it with `Value &v = get(..., Value{}); cout << v;` your program will crash, because `v` is a reference to the *temp* you created for `dfault`. And that will disappear at the `;`. When you `cout << v` it, it's gone. – towi Aug 24 '11 at 09:08