Which is more efficient: return value against Pass by reference?

I am currently learning how to write efficient C ++ code, and a question arises regarding function calls. Comparing this pseudo-code function:

not-void function-name () { do-something return value; } int main () { ... arg = function-name(); ... } 

with this otherwise identical pseudo-code function:

 void function-name (not-void& arg) { do-something arg = value; } int main () { ... function-name(arg); ... } 

Which version is more efficient and in what respect (time, memory, etc.)? If it depends on when the first will be more effective, and when will the second be more effective?

Change For context, this issue is limited to hardware platform-independent differences, and mainly software. Are there machine-independent performance differences?

Change I do not see how this is a duplicate. Another question is comparing the passage through the link (previous code) when passing through the value (below):

 not-void function-name (not-void arg) 

This is not the same as my question. My focus is not on what is the best way to pass an argument to a function. In my opinion, this is the best way to pass the result out for a variable from the outer scope.

+50
c ++ function
Nov 30 '15 at 9:14
source share
7 answers

First of all, keep in mind that returning an object will always be more readable (and very similar in performance) than passing it by reference, so it may be more interesting for your project to return the object and increase readability without important performance differences. If you want to know how to get the lowest price, you need to return:

  • If you need to return a simple or basic object, the performance will be the same in both cases.

  • If the object is so large and complex, a copy is needed to return it, and it may be slower than having it as a reference parameter, but it will spend less memory, I think.

You should still think that compilers do a lot of optimizations that make both executions very similar. See Copy Elision .

+18
Nov 30 '15 at 9:21
source share

Well, you need to understand that compilation is not a simple business. there are many considerations when the compiler compiles your code.

You can’t just answer this question, because the C ++ standard does not provide a standard ABI (abstract binary interface), so each compiler is allowed to compile the code that he likes, and you can get different results in each compilation.

For example, in some projects, C ++ is compiled for the Microsoft CLR managed extension (C ++ / CX). since everything that already has a reference to an object on the heap, I think there is no difference.

The answer is not simplified for unmanaged compilation. several questions come to mind when I think about "Will XXX work faster than YYY?", for example:

  • Are you object stupid?
  • Does your compiler support return value optimization?
  • Does your object support Copy-only semantics or copy and move?
  • Is the object packed according to (e.g. std::array ) or has a pointer to something on the heap? (e.g. std::vector )?

If I give a concrete example, I assume that on MSVC ++ and GCC, the return of std::vector by value will be passed by reference, due to r-value optimization, and will be slightly (several nanoseconds) faster than returning a vector by moving. for example, it could be completely different from Clang.

Profiling is the only true answer, after all.

+7
Nov 30 '15 at 9:33
source share

Object return should be used in most cases due to copy elision optimization.

However, depending on how your function is intended to be used, it may be better to pass the object by reference.

Take a look, for example, at std::getline , which takes std::string by reference. This function is intended to be used as a loop condition and continues to fill std::string until EOF is reached. Using the same std::string allows you to repeat the use of std::string storage space in each iteration of the loop, which significantly reduces the number of memory allocations that need to be performed.

+4
Nov 30 '15 at 9:29
source share

Some of the answers touched on this, but I would like to emphasize in the light of editing

In the context, this issue is limited to hardware platform-independent differences, and mainly software. Are there machine-independent performance differences?

If these are the limits of the question, the answer is that there is no answer. The C ++ specification does not provide for how either returning an object or passing by reference is implemented in terms of performance, but only the semantics of what they both do in terms of code.

Thus, the compiler can optimize the same code, since the other assumes that this does not create a noticeable difference with the programmer.

In light of this, I believe that it is best to use what is most intuitive for the situation. If the function really "returns" the object as a result of some task or request, return it, and if the function performs an operation on some object belonging to the external code, follow the link.

You cannot generalize performance on this. As a start, do everything that is intuitive and see how well your target system and the compiler optimizes it. If after profiling and detecting a problem, change it if you need to.

+3
Nov 30 '15 at 19:35
source share

This pseudo-code function:

 not-void function-name () { do-something return value; } 

best used when the return value does not require any additional changes on it. The last parameter is changed only in function-name . There are no more links for this.




otherwise identical pseudo-code function:

 void function-name (not-void& arg) { do-something arg = value; } 

it would be useful if we had another method that softens the value of the same variable as we do, and we need to save the changes made to the variable by one of the calls.

 void another-function-name (not-void& arg) { do-something arg = value; } 
+2
Nov 30 '15 at 9:20
source share

We cannot be 100% shared because different platforms have different ABIs, but I think we can make some fairly general statements that will be applied in most implementations with the caution that these things mainly apply to functions that are not included.

First, consider primitive types. At a low level, the pass by reference parameter is implemented using a pointer, while primitive return values ​​are usually passed literally to registers. Therefore, return values ​​are more likely to work better. On some architectures, this applies to small structures. Copying a value small enough to fit in a register or two is very cheap.

Now consider larger, but still simple (default constructors, copy constructors, etc.). Usually, larger return values ​​are handled by passing the function a pointer to the place where the return value should be given. Copying elision allows you to return a variable from a function, a temporary one, used to return, and a variable in the caller that the result is placed in a unit. Thus, the basics of transmission will be the same for transmission by reference and return.

In general, for primitive types, I would expect the return values ​​to be slightly better for larger, but still simple types, I would expect them to be the same or better if your compiler is not very bad at copying.

For types using default constructors, copy constructors, etc. things get more complicated. If the function is called several times, then the return values ​​will force the object to be rebuilt each time, while the reference parameters may allow the reuse of the data structure without being restored. On the other hand, the reference parameters will force the (possibly unnecessary) construct before calling the function.

+2
Nov 30 '15 at 13:36
source share

Performance, copies are usually more expensive, although the difference may be negligible for small objects. In addition, your compiler can optimize the reverse copy in the course, which is equivalent to passing the link.

I would recommend not passing const links unless you have a good reason. Use the return value (for example, the tryGet() sort function).

If you want, you can measure your difference, as others have said. Run the test code several million times for both versions and see the difference.

+1
Nov 30 '15 at 9:31
source share



All Articles