简体   繁体   中英

Calling move constructor when returning an rvalue-reference

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 (ie 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?

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.

Pre-C++20

The code is ill-formed for Pre-C++20 standard version as class.copy.elision states:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM