Friday 12 January 2018

c++ - inline void addTask(Task task) vs inline void addTask(const Task &task)

itemprop="text">



I used to pass
every complex structure by const & or at least by
&. But with the new std::move
semantic and all the optimizations that compilers offer today, is it still
the option to go?



Consider such
example:



struct
Task{

unsigned timeMS;
void(*function)(unsigned,
unsigned) = 0;
Task(unsigned timeMS, void(*function)(unsigned, unsigned))

: timeMS(timeMS),
function(function){}
};

class Timeline{

std::vector tasks;

...
};


class
App{
...
public:
inline void addTask1(const Task
&task){ timeline.add(Task); }
inline void addTask2(Task &task){
timeline.add(Task); }
inline void addTask3(Task task){ timeline.add(Task);
}
};



Which
one of addTask1, addTask2, addTask3 is the way to
go?
Assume that App::addTask() is an heavily
used method.



I guess that const
&
requires to create a copy, but I've learned that things are not as
simple as they look. It's enough to mention RVO ( href="http://en.wikipedia.org/wiki/Return_value_optimization"
rel="nofollow">http://en.wikipedia.org/wiki/Return_value_optimization) -
and I'm sure that there are much more things that should be taken into account (and I'm
not aware of them yet).



I know that
inline is in fact just the suggestion for compiler, rather then
an order. But does it change anything in const & vs
& vs by value
battle?



I am working with VC++ 2013, I'm not
focused on gcc too much.



P.s. Note that
App::addTask call Timeline::add which
call vector::push_back. So the parameter is
passed more then once
- should I make both
App::addTask and Timeline::add of the
same "type" (const & vs & vs
by value).


class="post-text" itemprop="text">
class="normal">Answer





Whether pass by value or
const& is appropriate depends, obviously what's done next
with the object. Especially when a copy of an object is needed in some form and the
objects being passed are likely to originate from temporary objects, using pass by value
is probably preferable: when passing by value the compiler is allowed to elide the copy.
When passing by const& copy elision is not allowed (for the
copy to be elided the compiler would need to prove that creating a copy doesn't have
observable side-effects).



Of course, when
passing by value the value happens to be an lvalue, i.e., to have it moved rather than
copied, you'll need to std::move() it when passing on (the
further copy can't be elided
anyway):



void addTask3(Task task)
{ timeline.add(std::move(task));
}


BTW, you omitted the
perfect forwarding
version:



template             T>

void addTask4(T&& task) {
timeline.add(std::forward(task));
}


This version won't
be allowed to elide copies, either, but it may have the advantage to create a more
expensive version in-situ based on a suitable
conversion.



I don't have any benchmarks to
determine the difference, though. If someone could suggest a decent way to benchmark the
differences I'm happy to add a corresponding benchmark to my suite of benchmarks and
augment this answer with the results.


No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...