简体   繁体   中英

Why isn't rvalue copy constructor used for assignment from temporary?

#include<iostream>
#include<vector>
#include<string>
using namespace std;
class test {
public:
    test(int y) {
        printf(" test(int y)\n");
    }
    test() {
        printf(" test()\n");
    }
    test(test&&c) noexcept {
        printf(" test(test&&c) noexcept\n");
    }
     test(const test&z) {
        printf(" test(const test&z)\n");
    }
    test& operator=( test&&e) {
        printf(" test& operator=( test&&e)\n");
        return *this;
    }
};
int main()
{
    test o ;
    o = 4;
    return 0;
}
The Output :
 " test() "
 " test(int y) "
 " test& operator=( test&&e ) "

I thought that this line in the code o = 4 is creating an rvalue of object of the class ( test ) and passing it to the overloaded operator ( operator = )

But when i changed

test& operator=( test&&e )

into

test& operator=( test e )

and run the code again:

#include<iostream>
#include<vector>
#include<string>
using namespace std;
class test {
public:
    test(int y) {
        printf(" test(int y)\n");
    }
    test() {
        printf(" test()\n");
    }
    test(test&& c) noexcept {
        printf(" test(test&&c) noexcept\n");
    }
    test(const test& z) {
        printf(" test(const test&z)\n");
    }
    test& operator=(test e) {
        printf(" test& operator=( test e)\n");
        return *this;
    }
};
int main()
{
    test o;
    o = 4;
    return 0;
}
   The Output :
     " test() "
     " test(int y) "
     " test& operator=( test e ) "

While I expected this Output after the change:

     " test() "
     " test(int y) "
     " test(test&&c) noexcept "
     " test& operator=( test e ) "

Because when i changed

test& operator=( test&&e )

into

test& operator=( test e )

the overloaded operator ( operator = ) now takes an object of the class test as parameter ( pass by value ) and the value that is passed to it is an rvalue so I expected that the constructor test(test&&c) noexcept will be called

So why the constructor

test(test&&c) noexcept  

is not called?

Explanation why I have this expectation:

because when you write this code and run it:

#include<iostream>
#include<vector>
#include<string>
using namespace std;
class test {
public:
    test(int y) {
        printf(" test(int y)\n");
    }
    test() {
        printf(" test()\n");
    }
    test(test&& c) noexcept {
        printf(" test(test&&c) noexcept\n");
    }
    test(const test& z) {
        printf(" test(const test&z)\n");
    }
    test& operator=(test e) {
        printf(" test& operator=( test e)\n");
        return *this;
    }
};
int main()
{
    test o;
    test x;
    o = move(x); // this function ( move () ) returns an rvalue of its argument 
    return 0;
}


The Output :
     " test() "
     " test() "
     " test(test&&c) noexcept "
     " test& operator=( test e ) "

edit: this code

#include<iostream>
#include<vector>
#include<string>
using namespace std;
class test {
public:
    test(int y) {
        printf(" test(int y)\n");
    }
    test() {
        printf(" test()\n");
    }
    test(test&& c) noexcept {
        printf(" test(test&&c) noexcept\n");
    }
    test(const test& z) {
        printf(" test(const test&z)\n");
    }
    test& operator=(test e) {
        printf(" test& operator=( test e)\n");
        return *this;
    }
};
int main()
{
    test o;
    test x;
    o = x;
    return 0;
}
   

The Output :
     " test() "
     " test() "
     " test(const test&z) "
     " test& operator=( test e ) " 

So why the constructor test(test&&c) noexcept is not called?

This is due tonon-mandatory copy elison prior to C++17.Under certain circumstances, the compilers are permitted , but not required to omit the copy and move (since C++11) construction of class objects .

You can verify this by providing the flag -fno-elide-constructors in your 2nd example. And you'll get your expected output. Demo .

class test {
public:
    test(int y) {
        printf(" test(int y)\n");
    }
    test() {
        printf(" test()\n");
    }
    test(test&& c) noexcept {
        printf(" test(test&&c) noexcept\n");
    }
    test(const test& z) {
        printf(" test(const test&z)\n");
    }
    test& operator=(test e) {
        printf(" test& operator=( test e)\n");
        return *this;
    }
};
int main()
{
    test o;
    o = 4;
    return 0;
}

Output with -fno-elide-constructors flag:

test()
test(int y)
test(test&&c) noexcept
test& operator=( test e)

Working demo .


And if you don't provide this flag, then compilers are allowed to elide the copy/move construction in this situation and hence you were getting the output you mentioned.


C++17

Note that from C++17 onwards, the flag -fno-elide-constructors won't have any effect on the output becasue of the mandatory copy elison .

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