2

Which clause in the C++11 Standard supports the move constructor call in the return of the function foo() below?

#include <iostream>

class A
{
    public:
    A() { std::cout << "Ctor\n"; }
    A(const A&) {std::cout << "Copy ctor\n";}
    A(A&&) {std::cout << "Move ctor\n";}
};

A foo(A&& ra) { return std::move(ra); }

int main()
{
    A a = foo(A());
}

This question was closed I believe yesterday, now it was placed "on hold" and the reason for the closing was that it's too localized. It's difficult for me to understand how a post in SO asking a specific question about the C++11 Standard could be considered "too localized". For me this is a contradiction in terms, as the Standard is "de facto" the final document that every C++ programmer should look for, in case of doubt about the language.

Belloc
  • 6,318
  • 3
  • 22
  • 52
  • 3
    The return type of `std::move(ra)` is `A&&` so when constructing the return value from `foo()` overload resolution chooses the constructor taking `A&&`. What exactly are you asking? – Jonathan Wakely Jun 25 '13 at 13:56
  • 2
    @JonathanWakely: This is somewhat deceptive. A function with a return value of `T&&` produces an xvalue which happens to bind to a parameter of type `T&&`, but in other contexts an entity of type `T&&` will not bind to a parameter of type `T&&`. One could be forgiven for thinking incorrectly that `T&&` binds to `T&&` because they are the same type. – Andrew Tomazos Jun 25 '13 at 14:30
  • Fair point, more accurately, the return type of `std::move(ra)` is `A&&` _which is an rvalue_, so overload resolution chooses the constructor taking `A&&`. (I don't think mentioning xvalues helps, the returned xvalue is also an rvalue, and rvalues binding to rvalue-references is easier to explain.) – Jonathan Wakely Jun 25 '13 at 16:17

1 Answers1

3

There are lots of clauses about the code. Specifically initialization (back of clause 8), overload resolution (clause 13) and more basically clause 3 and 5 to understand value categories of expressions and reference types.

First the expression A() is a class prvalue resulting from the default construction of a temporary.

It initializes the rvalue reference ra by direct reference binding.

ra initializes the parameter of move by direct reference binding, and move returns an xvalue of type A, again initialized by direct reference binding, which initializes the return value of foo, by overload resolving to the move constructor, moving the first temporary into the return value of foo, also a temporary.

The expression foo(A()) is a class prvalue refering to the second temporary.

This would then normally copy-initialize a by overload resolving the prvalue to the move constructor, and move constructing a from the return value of foo - however due to 12.8/32p3:

when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

Therefore the return value of foo is usually directly constructed it in the storage of a, and this second move construction is elided.

Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319
  • 2
    There's no copy elision on the return of foo(), according to 12.8p31 bullet point 1. The expression in the return statement must coincide with the function return type. – Belloc Jun 25 '13 at 12:38
  • What I'm saying is that there´s only one copy/move operation from the xvalue in the return statement to the variable `a`, and this copy/move cannot be elided by 12.8p31. What I'm looking for is the clause in the Standard that supports the move constructor to be selected to make this movement from an xvalue to an lvalue. I know this is the expected behavior. I'm just trying to get acquainted with the Standard. – Belloc Jun 25 '13 at 14:04
  • 1
    @user1042389: There is no copy ellison on __the construction__ of the return value of `foo`, however the copy-initialization of `a` __by__ the return value of foo, is elided. – Andrew Tomazos Jun 25 '13 at 14:20
  • 1
    @user1042389: You mean the overload resolution with an xvalue argument - you want to know why it selects the move constructor. See [this answer](http://stackoverflow.com/a/17130847/1131467) – Andrew Tomazos Jun 25 '13 at 14:22