-3

I am new to C++ and am trying to understand rvalue references and move semantics.

I have written a simple class, Class, which includes a method, fun, which creates an instance of the class in its body and returns it. The class has a copy constructor, a move constructor, a (copy) assignment operator, and a (move) assignment operator.

The following

Class obj2(obj1.fun()); // ??

obj3 = obj2.fun();      // (move) Assignment operator

neither calls the copy constructor nor the move constructor and calls the (move) assignment operator, respectively.

How does obj2 get created? Why doesn't

Class obj2(obj1.fun());

call the move constructor,

Class obj2(std::move(obj1.fun()));

does call the move constructor, and

obj3 = obj2.fun()

calls the (move) assignment operator (without needing to write std::move(obj2.fun()) like in the move constructor case)?

Many thanks!

tossimmar
  • 129
  • 5
  • 1
    This question is asked [very frequently](https://www.google.com/search?rlz=1C1CHBF_deDE833DE833&biw=1600&bih=789&sxsrf=ALeKk01tl1aGRpTI0Y_2bMmOUanFbfkJzA%3A1607705232529&ei=kKLTX_TlH4S-kwXGwqHACg&q=site%3Astackoverflow.com+%22c%2B%2B%22+move+constructor+not+called&oq=site%3Astackoverflow.com+%22c%2B%2B%22+move+constructor+not+called&gs_lcp=CgZwc3ktYWIQAzoECAAQR1Cw7P8BWITAgAJg_8SAAmgCcAJ4AIABhwGIAZkUkgEEMjEuNpgBAKABAaoBB2d3cy13aXrIAQjAAQE&sclient=psy-ab&ved=0ahUKEwj07abasMbtAhUE36QKHUZhCKgQ4dUDCA0&uact=5). Did you check the other posts? – πάντα ῥεῖ Dec 11 '20 at 17:56
  • _"I prefer Remy Lebeau's answer below."_ Fine, I'm closing your question as duplicate though, so that others researching in future will have a chance to find the link to that duplicate (which has a few answers more). – πάντα ῥεῖ Dec 11 '20 at 18:28

1 Answers1

4

Why doesn't Class obj2(obj1.fun()); call the move constructor

Because of Copy Elison. The compiler sees that fun() returns a temporary object, and that temporary will only be used to initialize obj2, so the compiler optimizes the creation of obj2 by eliminating the temporary object altogether and allowing obj2 to be created directly inside of fun() itself, thus there is no need for a copy/move operation when fun() exits.

Class obj2(std::move(obj1.fun())); does call the move constructor

Because you are forcing it with the explicit std::move type-cast, so the compiler can't optimize the creation of obj2 via Copy Elison, so it has to allow fun() to return a temporary object, which you are then moving into the obj2 constructor.

obj3 = obj2.fun() calls the (move) assignment operator

Because obj3 already exists before the assignment.

without needing to write std::move(obj2.fun())

Because fun() returns a temporary object, which is an rvalue, so there is no need to explicitly type-cast it to an rvalue when calling a move assignment operator.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770