Mateusz Pusz
Mateusz Pusz

Reputation: 1393

How to effectively pass arguments through many functions

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

Answers (2)

RiaD
RiaD

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 moves 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

Red XIII
Red XIII

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

Related Questions