Search code examples
c++c++11standardsmove

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


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.


Solution

  • 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.