0
#include <iostream>

class Box{
public:
int x;
Box(){
    x=0;
    std::cout << "Constructor" << std::endl;
}
Box(const Box& other){
    x = other.x;
    std::cout << "Copy constructor" << std::endl;
}
Box(Box&& other){
    x = other.x;
    other.x = 0;
    std::cout << "Move constructor" << std::endl;
}

Box& operator=(Box&& other) {
    x = other.x;
    other.x = 0;
    std::cout << "Move assignment" << std::endl;
    return *this;
}

Box& operator=(const Box &other){
    x = other.x;
    std::cout << "Copy assignment" << std::endl;
}

~Box(){
    std::cout << "Destructor" << std::endl;
    x=0;
}
};
Box send(Box b){
std::cout << "Sending" << std::endl;
return b;
}
int main(){
Box b1, b2;
b1 = send(b2);
return 0;
}   

In the output:

Constructor
Constructor
Copy Constructor
Sending
Move Constructor
Move Assignment
Destructor
Destructor
Destructor
Destructor

I'm not too sure why a move constructor then assignment was used when doing b1 = send(b2).

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • You have to create a temporary return value. – Henri Menke Feb 22 '18 at 10:09
  • I guess (don't quote me on that) it is because you create a copy of a Box in the send function, since it is deleted when leaving the scope of the function anyway, it calls the move assignment because the return value can be treated as rvalue. Can't check it at the moment though, it's just my guess – Plebshot Feb 22 '18 at 10:10

2 Answers2

1

It's move-constructing the return value from the parameter b, then that return value is move-assigned to b1.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
1

Why is the move constructor/assignment called when setting an object equal to the return value of another function

Your send function returns b that is a parameter, not a local variable:

Box send(Box b) {
    std::cout << "Sending" << std::endl;
    return b; // b is a parameter
}

So there is no RVO optimization occuring, because returning a parameter disables RVO. Meanwhile, there's another optimization option available, an implicit std::move:

Box send(Box b) {
    std::cout << "Sending" << std::endl;
    return std::move(b); // implicit std::move is applied.
}

So it's constructed, using your move constructor:

Box(Box&& other);

You'll see no move construction if you create and return a local variable c instead:

Box send(Box b) {
    Box c;
    std::cout << "Sending" << std::endl;
    return c; // Returns c, not b -> No move construction thanks to RVO
}

because RVO then jumps in.

Dean Seo
  • 5,486
  • 3
  • 30
  • 49