0

hey guys am still learning c++ but am just kind of confused about move constructors and copy constructors.

first i have a simple function that set a value to an object

#include <iostream>
#include "item.hpp"
#include "player.hpp"

player giveHealth(player user, int value) {
    user.set_health(value);
    return user;
}

int main() {
    player a;
    player b(a);
    
    a = giveHealth(a, 100);
    
    return 0;
}

as you see i didnt add && on the return type but it still call's the move constructor at the end of the givehealth() function?

  • 1
    When you are returning local objects from function, move constructor is called automatically (unless (N)RVO kicks in, and no copies are made at all). – SergeyA Jun 18 '21 at 15:28
  • Does this answer your question? [C++11 rvalues and move semantics confusion (return statement)](https://stackoverflow.com/questions/4986673/c11-rvalues-and-move-semantics-confusion-return-statement) – ph3rin Jun 18 '21 at 15:32
  • @SergeyA what confuse me is why move constructor is called unstead of copy constructor, like i guess the move constructor is called when u declare the return type with reference symbole (&&), isn't it ? – Kias Mohamed Islam Jun 18 '21 at 15:34

2 Answers2

0

as you see i didnt add && on the return type

&& would make the return type a reference. If you were to return a reference, then there wouldn't be a move. But you'd be returning a reference to a local variable which would have been destroyed at the end of the function and as such the returned reference would always be danging. Don't do that.

Although user in return user; is an lvalue, and as such you might expect there to be a copy, this is a special case where because user is a local variable, the move constructor is used instead. This language rule is possible, because the local variable is about to be destroyed, and thus it is safe to be moved from.

eerorika
  • 232,697
  • 12
  • 197
  • 326
0

See cppreference under "Automatic move from local variables and parameters".

The compiler does that.

If expression ... variable ... is declared as a parameter of the innermost enclosing function...
then overload resolution to select the constructor to use for initialization of the returned value ... is performed twice:
first as if expression were an rvalue expression (thus it may select the move constructor),

Colloquially, the return variable; is automatically turned into return std::move(variable);.

JDługosz
  • 5,592
  • 3
  • 24
  • 45
  • I don't really like that simplification as it masks the true reason. In OP's code, `user` is an eXpirering value (xvalue) and xvalues do bind to rvalue references (`&&`). Per design, the move constructor is preferred over the copy constructor when both could apply. – YSC Jun 18 '21 at 16:08
  • 1
    @YSC `user` is not an xvalue. It is an lvalue. JDługosz's simplification is nearly identical with your explanation given that `std::move(variable)` would be an xvalue. But if either your or their explanation were exactly accurate, then `return user;` wouldn't work with a type that has a deleted move constructor and non-deleted copy constructor... but it works. – eerorika Jun 18 '21 at 18:01