Reputation: 1393
From some time we can hear a lot that value semanthics is really important in C++ (i.e. here and here). I know that we should use it especially when we intend to copy the value inside the body of the function anyway. So I assume that such a usage is fair:
void foo(std::string txt) { my_container.emplace_back(move(txt)); }
However I did not find any recommendation what to do if I have to pass that argument through a big tree of functions which sometimes happens in a big project. So for example:
void bar(std::string txt) { foo(move(txt)); /* more actions */ }
void boo(std::string txt) { bar(move(txt)); /* more actions */ }
Can someone recommend what to do in such a case? Should we stay with value semantics and hope that compiler optimizer will be able to limit number of move operations or use const references everywhere and only one copy at the end? Or maybe, as in many cases in C++, it depends (i.e. cost of copy and move for specific type)? :-)
Upvotes: 8
Views: 531
Reputation: 47658
In general it depends on cost of copy and move for specific type(and even objects) and how it's called(with temporaries or not, etc)
For example for temporary boo(gimme_t())
:
Let d
is depth of tree of yours classes
Solution with move
s cost d * COST_OF_MOVE
, solution with COST_OF_COPY + d * REF_ASSIGNMENT
.
You can see that for std::string
it's O(d)
vs O(n)
so for strings with big lengths it's cheaper to use moves (and for short strings it's not so important), but for std::array<int>
it's O(nd)
vs O(n + d)
, so you'd better use one copy.
But if argument isn't temporary (T t; boo(t)
) costs will be:
COST_OF_COPY + d * COST_OF_MOVE
vs COST_OF_COPY + d * REF_ASSIGNMENT
, so const-ref solution is faster by d
moves.
But if you may consider move
almost free™ you'd better use move solution to avoid 1 copy in case of temporary argument
(*) Everywhere you should read d ± 1
instead of d
Upvotes: 1
Reputation: 6047
For templates and template-like solutions you should obviously go with perfect forwarding. In other cases, forcing a copy via foo(MyType copy)
declaration seems needles. Avoid costs, and copy when you must, even if via copy-elision the compiler might be little more efficient than move operations.
Upvotes: 0