A have a few questions regarding copy elision and move. Let's assume I have the following code:
class A {};
class B {
public:
A get1() const {
A local_var;
return local_var;
}
A get1bad() const {
A local_var;
return std::move(local_var);
}
A get2() const {
return member_var;
}
A get3() const {
return std::move(member_var);
}
private:
A member_var;
};
I read a lot of people saying to not do move on return. From what I gather it's because with copy elision, on case get1, the compiler will not call constructor move constructor but rather just one call to the default constructor, while case get1bad forces the compiler to call constructor move.
My question is regarding cases where the variable is not local (get2 vs get3). In that case, the variable is constructed anyway in the class. In get2 there's not really any optimization that I can see being possible. In this case, if I don't really care about ensuring class B has a valid A object, wouldn't it be better to actually move? Wouldn't it just call the move constructor which is generally cheaper than the copy constructor?
CodePudding user response:
A get3() const {
return std::move(member_var);
}
You have a const function, so the member is also considered const and will not move anyway.
You could consider A get3() &&
to move the member when you have a temporary B
. Maybe, if that happens often.
Having a getter that always destroys the class' value, even when it is an lvalue, seems like a rare use case.
CodePudding user response:
I read a lot of people saying to not do move on return. From what I gather it's because with copy elision, on case get1, the compiler will not call constructor move constructor but rather just one call to the default constructor, while case get1bad forces the compiler to call constructor move.
If the operand to a return
statement is just the name of a local variable, then std::move
is basically implicitly applied. So at best return std::move(local_var);
is redundant. This is a special rule for return
. It doesn't apply elsewhere.
However, using return std::move(local_var);
makes it so that the mandatory copy elision rules do not apply anymore, which is why it is not only redundant, but even worse than just return local_var;
.
My question is regarding cases where the variable is not local (get2 vs get3). In that case, the variable is constructed anyway in the class. In get2 there's not really any optimization that I can see being possible. In this case, if I don't really care about ensuring class B has a valid A object, wouldn't it be better to actually move? Wouldn't it just call the move constructor which is generally cheaper than the copy constructor?
In your examples all member functions are const
qualified. Therefore the type of std::move(member_var)
will be const A&&
. The move constructor takes a A&&
, not const A&&
. Therefore no move will happen and the copy constructor will be used for both get2
and get3
's return values.
If you remove the const
qualifiers, then yes return std::move(member_var);
makes sense in that case and allows a move construction rather than copy construction. Copy/move elision is not possible in either case, since variable is not local to the function.
It is unlikely that you wouldn't care about the state of member_var
after calling a member function, so it is unlikely that this will make sense in practice. If at all I would qualify the member function with &&
, so that it is only used if the class instance is an rvalue, which is the only case I can think of where one doesn't care about the object state after the call to the member function.