Home > Back-end >  Calling move constructor when returning an rvalue-reference
Calling move constructor when returning an rvalue-reference

Time:05-29

This is a follow-up question of my previous question.

Consider the following toy code:

#include <iostream>
using namespace std;
class X
{
public:
    X() { }

    X(X&& x)
    {
        cout << "move ctor\n";
    }

    /*X(X& x)
    {
        cout << "copy ctor\n";
    }*/

};

X f()
{
    static X x;
    X&& y = std::move(x);
    X& z = x;
    return y;
}

int main()
{
    f();
}

From my understanding on my previous question (i.e. class.copy.elision#3), I think it would cause an error (use of deleted function 'constexpr X::X(const X&)') in the above code to return y in f().

The thing is, I run the code in Visual Studio on my PC and it compiles and prints move ctor. So I test the code online using other compilers, and the results are that msvc and clang compile successfully while gcc gives the error that I'm expecting.

May I humbly ask if this is a bug of msvc and clang, and the program ought not to compile?

CodePudding user response:

The code is legal since C 20, according to cppreference.

There's a rule that returning a non-reference non-volatile local variable implicitly moves it. C 20 added the same rule for rvalue references to non-volatile types.

GCC accepts the code with -std=c 20. I'm unsure why Clang and MSVC accept it in earlier standard revisions, but I don't see this as a problem.

CodePudding user response:

Pre-C 20

The code is ill-formed for Pre-C 20 standard version as it says:

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

(emphasis mine)

as you can see there is no mention of rvalue reference in the above quoted statement. And so there seems to be a bug in msvc and clang as they compile it for Pre-C 20.


C 20

But C 20, specifically allows the use of rvalue reference as quoted below:

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 is first considered before attempting a copy operation:

  • If the expression in a return ([stmt.return]) or co_­return ([stmt.return.coroutine]) 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 or lambda-expression, or

(emphasis mine)

Thus the code is legal from C 20 and onwards and the move constructor can be used.

  • Related