0

So this seems like a fairly simple question, but I haven't been able to find an answer to it anywhere online. The reason I'm assuming a function which returns a variable is less efficient than a function which takes a variable and changes it is because I think the first would use more memory. However, I could be wrong, I'm not aware of how this affects processing time.

Here's two C++ examples: This a function which returns a variable:

#include <iostream>
short getInput(){
    short input;
    std::cin >> input;
    return input;
}
int main(){
    short input = getInput();
}

You can see in this one that the program needs two input variables to be created, even if the second is only created for a brief amount of time.

This is a function which passes a value by reference:

#include <iostream>
short getInput(short& input){
    std::cin >> input;
}
int main(){
    short input;
    getInput(input);
}

Not only is this example code segment shorter, it only initializes one short variable. Am I wrong on the fact that it's more efficient.

Logan Kling
  • 569
  • 2
  • 6
  • 19
  • what's your use case? – Alleo Indong Jun 05 '15 at 05:43
  • 1
    Well you can return only one variable from a function where as with reference variables you can work with as many variables you want. – Sourav Kanta Jun 05 '15 at 05:45
  • 1
    For built in types, its better to return an object by value. – R Sahu Jun 05 '15 at 05:46
  • 1
    http://ericniebler.com/2013/10/13/out-parameters-vs-move-semantics/ – Pradhan Jun 05 '15 at 05:48
  • 1
    @SouravKanta you can return a `std::tuple` if you want a "multi-value". In any case, for class objects (where the performance may make a difference), named returned value optimization (NRVO) takes care of business, so there shouldn't be any performance difference. – vsoftco Jun 05 '15 at 05:50
  • Do you know [RVO](http://en.wikipedia.org/wiki/Return_value_optimization)? – songyuanyao Jun 05 '15 at 05:52
  • @RSahu Why is that better? – Logan Kling Jun 05 '15 at 05:53
  • @LarryK Performance is not an issue for fundamental types, this is really micro-optimization. And getting rid of output parameters makes your code much more elegant and easy to read. Imagine writing something like `sin(exponential(factorial(n)))` with output parameters for all 3 functions. Not pretty. In fact, impossible, you'd need additional storage. – vsoftco Jun 05 '15 at 05:54

2 Answers2

3

A value of a small, simple built-in type like short or int is almost certain to be returned in a register, so it won't involve creating anything.

If we simplified your code a tiny bit to something like return 1;, we'd expect the body (when we turned off optimization, so there was still code for anything at all) we'd end up with something like this:

mov rax, 1
ret

If the return value is not small enough to fit in a register, then the compiler is normally going to allocate space in the caller, and pass a hidden reference to that space to the function being called. In other words, it'll do essentially the same thing you're doing manually.

To make a long story short, you should write your code whichever way makes the most sense. If if makes the most sense for your function to return a value, then return a value. If it makes more sense to pass a reference, then do that.

There are a few cases where it makes real sense to modify a referenced variable instead of returning a value though. One is for something like a pop from a stack or a queue. If copying a return value might throw, then there can be a difference in exception safety. For example, you can do something like this:

template <class T>
class queue {
    std::deque<T> data;
public:
    void pop(T &t) { 
        t = data.front();
        data.pop_front();
    }
};

If you attempt to return the T by value, you can end up popping the value off the deque, but then its copy constructor throws when you try to copy the return value.

This way, however, you're only popping the value off the deque if the copy into the "return" value succeeds. If the copy throws, then the value remains on the deque.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
1

I will attempt an answer, although I'm sure it is probably debatable. I strongly support returning by value instead of using output parameters for the following reasons:

  1. Returning fundamental types by value is extremely efficient. Returning by value also allows "natural" function composition, such as

    double result = sin(exponential(factorial(n)));
    

    Imagine writing this with output parameters for all 3 functions.

  2. Performance begins to matter whenever you return large class objects. However, in that case the compiler can (and does) perform the so called (named) return value optimization. This is an optimization scheme in which the (named) return value is constructed directly into the left hand side object (there are some restrictions, see the link). Furthermore, returning by value plays nicely with C++11 move semantics, so if you have a cheap-to-move object of some type, say Foo, you can write

    my_already_constructed_object = some_function_that_returns_by_value();
    

    and the move assignment operator will do its magic, which is effectively much cheaper than a deep copy (think of it more like a swap).

Community
  • 1
  • 1
vsoftco
  • 55,410
  • 12
  • 139
  • 252