Function in C++ Returns by Value or by Reference

C: When to return by value or pass reference

Start by deciding which approach makes the most sense at the logical level, irrespective of what you think the performance implications might be. If returning a struct by value most clearly conveys the intent of the code, then do that.

This isn't the 1980s anymore. Compilers have gotten a lot smarter since then and do a really good job of optimizing code, especially code that's written in a clear, straightforward manner. Similarly, parameter passing and value return conventions have become fairly sophisticated as well. The simplistic stack-based model doesn't really reflect the reality of modern hardware.

If the resulting application doesn't meet your performance criteria, then run it through a profiler to find the bottlenecks. If it turns out that returning that struct by value is causing a problem, then you can experiment with passing by reference to the function.

Unless you're working in a highly constrained, embedded environment, you really don't have to count every byte and CPU cycle. You don't want to be needlessly wasteful, but by that same token you don't want to obsess over how things work at the low level unless a) you have really strict performance requirements and b) you are intimately familiar with the details of your particular platform (meaning that you not only know your platform's function calling conventions inside and out, you know how your compiler uses those conventions as well). Otherwise, you're just guessing. Let the compiler do the hard work for you. That's what it's there for.

Function in C++ returns by value or by reference?

C++ functions can return by value, by reference (but don't return a local variable by reference), or by pointer (again, don't return a local by pointer).

When returning by value, the compiler can often do optimizations that make it equally as fast as returning by reference, without the problem of dangling references. These optimizations are commonly called "Return Value Optimization (RVO)" and/or "Named Return Value Optimization (NRVO)".

Another way to for the caller to provide an empty vector (by reference), and have the function fill it in. Then it doesn't need to return anything.

You definitely should read this blog posting: Want Speed? Pass by value.

Should I assign a ref or a copy to a value returning function?

Your colleague is trying to do the compiler's job instead of trusting it, and is potentially pessimizing as a result. NRVO is very well supported, and if the functions are written with value semantics, NRVO can elide multiple copies. Binding to a reference will prevent that, since a reference variable will not satisfy the conditions for this optimization. A simple test to demonstrate:

#include <iostream>

struct Test {
Test() { std::cout << "Created\n"; }
Test(const Test&) { std::cout << "Copied\n"; }
};

Test foo() {
Test t;
return t;
}

Test bar_good() {
const auto t = foo();
return t;
}

Test bar_bad() {
const auto& t = foo();
return t;
}

int main() {
const auto good = bar_good(); (void)good;

std::cout << "===========\n";

const auto& bad = bar_bad(); (void)bad;
}

Which gives the output:

Created
===========
Created
Copied

One object total when utilizing value semantics, but a redundant copy when using references. Depending on how expansive the copy (or even move) is, you could see a noticeable performance difference.

Why is returning by value the recommended way in C++?

Before considering returning a reference, you must first decide what object would the result refer to. What are your options?

  1. You could return reference to a local automatic variable... This is very bad because the local variable won't exist once the function returns.
  2. You could return reference to a variable in static or thread local storage. This is bad because global state is bad.
  3. You could return reference to an object that was provided as an argument by the caller. Well, in this case it's typically pointless to return the reference since the caller already knows where the object is since they were responsible in providing the argument in the first place. This is just a complicated version of the "output parameter" that was recommended against by the quoted text.

There of course are cases where returning a reference makes sense. General rules of thumb such as the quoted one don't apply to every case. They apply to most, simple cases. If you know a good reason to not follow it, then don't. If you don't know whether there is a reason, then follow the rule until you gain understanding.

It is important to note the context of the advice. The section begins with "if you have a function that needs to return an object of a class...". The context wasn't "if you have a function that needs to return reference to an object of a class".



I do return-by-reference for member functions that can be called in chain obj.DoX(...).DoY(...).DoZ(...);

Method chaining is an idiom where reference to *this is returned. So, this would be conventional. Technically, my point 3. above applies to this case. The caller already has obj, so why return a reference to it? In this case the answer is: The reference is returned for convenience.

I would say that the advice of the book applies well to functional programming paradigm.

Object oriented programming paradigm is quite different. A member function that modifies *this is in fact a function with an output parameter - the parameter being the implicit *this object - that is modified. So, the quoted rule of thumb can be seen as a recommendation against setter functions... or it could be seen as not being intended to apply to object oriented programming.

Store return value of function in reference C++

It is not allowed to bind the temporary to a non-const reference, but if you make your reference const you will extend the lifetime of the temporary to the reference, see this Danny Kalev post about it.

In short:

const A& mySecondObject = myFunction();

Why return an object passed by reference to the function in C++?

It allows you to compose fluent interfaces, like this

read_hw(cin, hw).read_something_else(cin, x).blah_blah(cin, y)

since each method call returns a reference to the istream object, it can be used to chain method calls.

That is in fact what happens when you do

cin >> a >> b;

Each operator>> function call returns a reference to the stream, so it can be chained.

It can also allow you to loop and read in from an istream object the idiomatic way in C++, for example

while (read_hw(cin, hw)) { 
do_something_with_hw(hw);
}

Passing return value of a function as reference

This "works" because of const int& ref - when a reference is const (guarantees that you don't want to change it), the compiler will produce a temporary object in the calling code (start in your case), and then pass the reference to that.

If you remove const it will fail to compile because functionA's result can't be turned into a reference.



Related Topics



Leave a reply



Submit