I followed the amazing tutorials from stackoverflow for Move and Operator overloading (e.g. What are the basic rules and idioms for operator overloading?), and the following situation is baffling me. Nothing fancy in the code, just printing when special member functions are called.
The main code:
class B {
public:
B() { std::cout << "B::ctor\n"; }
~B() { std::cout << "B::dtor\n"; }
B(B const &b) {
std::cout << "B::copy ctor\n";
}
B &operator=(B const &rhs) {
std::cout << "B::copy assignment\n";
return *this;
}
B(B &&b) {
std::cout << "B::move ctor\n";
}
B &operator=(B &&rhs) {
std::cout << "B::move assignment\n";
return *this;
}
B &operator+=(B const &rhs) {
std::cout << "B::operator+=\n";
return *this;
}
};
int main() {
B b;
std::cout << "=== b = b + b + b ===\n";
b = b + b + b;
}
Now, two scenarios, where in each I define the operator + differently:
B operator+(B p1, B const &p2) {
std::cout << "B::operator+\n";
return p1 += p2;
}
with output for the whole program:
B::ctor
=== b = b + b + b ===
B::copy ctor
B::operator+
B::operator+=
B::copy ctor
B::operator+
B::operator+=
B::copy ctor
B::move assignment
B::dtor
B::dtor
B::dtor
B::dtor
and the second scenario:
B operator+(B p1, B const &p2) {
std::cout << "B::operator+\n";
p1 += p2;
return p1;
}
with output:
B::ctor
=== b = b + b + b ===
B::copy ctor
B::operator+
B::operator+=
B::move ctor
B::operator+
B::operator+=
B::move ctor
B::move assignment
B::dtor
B::dtor
B::dtor
B::dtor
How come the second scenario does give the expected result, using correctly the move semantics, but the first makes copy everywhere?
I just want to add that the second scenario is the one recommended in the tutorials I read (like the link from above), but when I tried to implement it, I intuitively wrote the first scenario and it gave me the wrong behaviour...