Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any efficiency benefit to passing primitive types by reference instead of returning by value?

In C++, is there an efficiency benefit in passing primitive types by reference instead of returning by value?

like image 321
user997112 Avatar asked Jun 16 '13 13:06

user997112


People also ask

Is passing by reference more efficient?

Pass-by-references is more efficient than pass-by-value, because it does not copy the arguments. The formal parameter is an alias for the argument. When the called function read or write the formal parameter, it is actually read or write the argument itself.

Should I always use pass by reference?

Always passing a reference and putting const in front of it is tedious and prone to errors. Also, always passing references would mean creating a local variable for each function argument (instead of passing expressions).

Which is generally more efficient a function that returns an object by reference or a function that returns an object by value?

Returning the object should be used in most cases because of an optimsation called copy elision. However, depending on how your function is intended to be used, it may be better to pass the object by reference.

Are primitive types passed by reference in Java?

Primitive types get passed by value, object references get passed by value. Java doesn't pass objects. It passes object references - so if anyone asks how does Java pass objects, the answer is: "it doesn't".


2 Answers

[...] is there an efficiency benefit to passing primitive types by reference instead of returning by value?

Unlikely. First of all, unless you have data from your profiler that give you a reason for doing otherwise, you should not worry about performance issues when designing your program. Choose the simplest design, and the design that best communicates your intent.

Moreover, primitive types are usually cheap to copy, so this is unlikely to be the bottleneck in your application. And since it is the simplest option and the one that makes the interface of the function clearest, you should pass by value.

Just looking at the signature, it is clear that a function such as:

void foo(int);

Will not store a reference to the argument (and consequently, won't run into issues such as dangling references or pointers), will not alter the argument in a way that is visible to the caller, and so on and so on.

None of the above can be deduced from a function signature like:

void f(int&); // May modify the argument! Will it? Who knows...

Or even:

void f(int const&); // May store a reference! Will it? Who knows...

Besides, passing by value may even improve performance by allowing the compiler to perform optimizations that potential aliasing would prevent.

Of course, all of this is under the assumption that you do not actually need to modify the argument inside the function in a way that side-effects on that argument will be visible to the caller after the function returns - or store a reference to that argument.

If that is the case, then you should of course pass by reference and use the appropriate const qualification.

For a broader discussion, also see this Q&A on StackOverflow.

like image 60
Andy Prowl Avatar answered Nov 10 '22 01:11

Andy Prowl


In general there won't be any performance benefit and there may well be a performance cost. Consider this code:

void foo(const int& a, const int& b, int& res) {
    res = a + b;
    res *= a;
}

int a = 1, b = 2;
foo(a, b, a);

When a compiler encounters a function like add() it must assume that a and res may alias as in the example call so without global optimizations it will have to generate code that loads a, loads b, then stores the result of a + b to res, then loads a again and performs a multiply, before storing the result back to res.

If instead you'd written your function like this:

int foo(int a, int b) {
    int res = a + b;
    res *= a;
    return res;
}

int a = 1, b = 2;
int c = foo(a, b);

Then the compiler can load a and b into registers (or even pass them directly in registers), do the add and multiply in registers and then return the result (which in many calling conventions can be returned directly in the register it was generated in).

In most cases you actually want the semantics in the pass / return by value version of foo and the aliasing semantics possible in the pass / return by reference version do not really need to be supported. You can end up paying a real performance penalty by using the pass / return by reference version.

Chandler Carruth gave a good talk that touched on this at C++ Now.

like image 30
mattnewport Avatar answered Nov 10 '22 00:11

mattnewport