2

I already know automatic move is not woking with the function which return value from Rvalue Reference input. But why?

Below is example code which automatic move is not working with.

Widget makeWidget(Widget&& w) {
  ....
  return w; // Compiler copies w. not move it.
}

If the function input is from copy by value, automatic move works.

Widget makeWidget(Widget w) {
  ....
  return w; // Compiler moves w. not copy it.
}
myoldgrandpa
  • 871
  • 7
  • 21
  • 3
    move is not copy elision. – apple apple Dec 08 '21 at 14:49
  • @appleapple This example is not RVO or NRVO. But compiler can optimize copy operation to move operation. So can't I call it copy elision? – myoldgrandpa Dec 08 '21 at 14:54
  • possible duplicate: https://stackoverflow.com/a/40187776/5980430 (although it looks like c++20 have change the rule as @songyuanyao 's answer shows. – apple apple Dec 08 '21 at 14:58
  • @appleapple Thanks for your comment. But my point is I already know this compiler behavior but why? Accepting this rvalue automatic move operation from c++20 means that many people just have same thought with me. Move optimization of above example seems straight forward but why c++ can't accept this till c++20 ? – myoldgrandpa Dec 08 '21 at 15:07
  • @OP in case it's unclear, I was linking to @ Yakk 's answer which contains some explanation. – apple apple Dec 08 '21 at 16:28

2 Answers2

5

The code should work as you expected since C++20; automatic move operation is performed when returning local variables and parameters, and it works for rvalue reference too (since C++20).

If expression is a (possibly parenthesized) id-expression that names a variable whose type is either

  • a non-volatile object type or
  • a non-volatile rvalue reference to object type (since C++20)

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
2

Relevant part of the C++17 standard [class.copy.elision/3]:

In the following copy-initialization contexts, a move operation might be used instead of a copy operation:

  • If the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function...

This does not hold for:

Widget makeWidget(Widget&& w)
{
  return w;
}

since w does not name an object with automatic storage duration (within the function).

In C++20, the situation is different:

An implicitly movable entity is a variable of automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. In the following copy-initialization contexts, a move operation might be used instead of a copy operation:

  • If the expression in a return or co_­return statement is a (possibly parenthesized) id-expression that names an implicitly movable entity declared in the body or parameter-declaration-clause of the innermost enclosing function...

Here, the reference w satisfies those requirements since it is an rvalue reference declared in the parameter-declaration-clause.

Why the same was not until C++20? I cannot say; likely nobody proposed such a change before.

Daniel Langr
  • 22,196
  • 3
  • 50
  • 93