I have an issue with clang-tidys recommendation
Clang-tidy: arg is passed by value and only used once; consider moving it.
So the code is essentially this:
struct S{
kinda_heavy obj;
S(kinda_heavy heavy):obj(heavy){}
void do_stuff();
};
I'm expecting the caller to use an x-value argument.
S app = S(get_kinda_heavy());
Or maybe the caller will use it like
{
auto env = get_kinda_heavy();
S s{env};
s.do_stuff();
}
I'm under the impression no copying of env
will take place here under normal circumstances, i.e the caller will understand if a copy is being made or not.
I'm hoping CTidys comment isn't applicable to me.
My reason for asking is I don't want to sprinkle my code with hints that aren't useful for the reader nor the compiled code.
Clarification for me: I think I'm asking; under what circumstance is this a zero copy operation?
Of course, the kinda_heavy
has both move and copy CTOR and assignment.
In the first case:
S app = S(get_kinda_heavy());
The temporary will bind to heavy
in the constructor object (no move, no copy) and then you copy it in the initialization statement:
S(kinda_heavy heavy):obj(heavy){}
If there was an explicit move
here as clang tidy suggests, then the 1 copy would turn into 1 move:
S(kinda_heavy heavy):obj(std::move(heavy)){}
That optimization was purposefully not added to the design so that there was no possibility of a double move. In more complicated code it is possible for heavy
to be used twice (since it has a name). And we did not wish to ask the compiler to prove that heavy
would only be used once, and perform an implicit move in that case. Since the original design, implicit moves have been added in more places. Imho if we add too many more, the design will become too clever by half and nobody will be able to remember the rules (if we're not there already).
In the second case:
auto env = get_kinda_heavy();
S s{env};
There is a copy when sending env
to bind to the argument constructor. And then there is a second copy in your initialization statement:
S(kinda_heavy heavy):obj(heavy){}
If you take clang-tidy's suggestion, the second copy would turn into a move.
under what circumstance is this a zero copy operation?
In your second case, there is no avoiding the copy of env
without an explicit move
:
auto env = get_kinda_heavy();
S s{std::move(env)};
Presumably the copy here is necessary so that the client does not see env
change value. In any event this copy is under the client's control. If the client prefers a move here he can do so explicitly.
As you have it coded, you have a copy in the initialization statement:
S(kinda_heavy heavy):obj(heavy){}
You can turn that into a move with clang-tidy's suggestion:
S(kinda_heavy heavy):obj(std::move(heavy)){}