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?
- You could return reference to a local automatic variable... This is very bad because the local variable won't exist once the function returns.
- You could return reference to a variable in static or thread local storage. This is bad because global state is bad.
- 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
Convert a Char* to Std::String
Lambda Capture as Const Reference
Move or Named Return Value Optimization (Nrvo)
What Is an Opaque Value in C++
Easiest Way to Rotate by 90 Degrees an Image Using Opencv
Effective Way to Select Last Parameter of Variadic Template
How Does *(&Arr + 1) - Arr Give the Length in Elements of Array Arr
Why Does C++ Not Let Baseclasses Implement a Derived Class' Inherited Interface
C++ Class Member Function Pointer to Function Pointer
How to Use Windbg to Analyze the Crash Dump for Vc++ Application
Calculating the Amount of Combinations
How to Change the Background Color of a Button Winapi C++
Does Casting to an Int After Std::Floor Guarantee the Right Result