E.g.
What's best out of these:
std::string f() {}
or
const std::string& f() {}
E.g.
What's best out of these:
std::string f() {}
or
const std::string& f() {}
Related to this question, I've just seen this article posted in another question:
http://www.ddj.com/database/184403855
If you return a reference to a variable that is local to the function then you're going to end up with issues (depending on the compiler and its settings).
If you return a reference to an instance that's still in scope when the function returns then it will be faster, as no copy of the string is being created.
So the latter is more efficient (technically) but may not function as expected depending on what you return a reference to.
A function should never return a reference to a local object/variable since such objects go out of the scope and get destroyed when the function returns.
Differently the function can return a const or non const reference to an object whose scope is not limited by the function context. Typical example is a custom operator<<
:
std::ostream & operator<<(std::ostream &out, const object &obj)
{
out << obj.data();
return out;
}
Unfortunately returning-by-value has its performance drawback. As Chris mentioned, returning an object by value involves the copy of a temporary object and its subsequent destruction. The copy takes place my means of either copy constructor or operator=. To avoid these inefficiency smart compilers may apply the RVO or the NRVO optimizations, but there are cases in which they can't -- multiple returns.
The upcoming C++0x standard, partially available in gnu gcc-4.3, introduces the rvalue reference [&&] that can be used to distinguish a lvalue from a rvalue reference. By means of that it's possible to implement the move constructor useful to return an object partially avoiding the cost of copy constructor and the destructor of the temporary.
The move constructor is basically what Andrei envisioned some years ago in the article http://www.ddj.com/database/184403855 suggested by Chris.
A move constructor has the following signature:
// move constructor
object(object && obj)
{}
and it's supposed to take the ownership of the internals of the passed object leaving the latter in a default state. By doing that copies of internals are avoided and the destruction of the temporary made easy. A typical function factory will then have the following form:
object factory()
{
object obj;
return std::move(obj);
}
The std::move() returns a rvalue reference from an object. Last but not least, move constructors allow the return-by-rvalue-reference of non-copyable objects.
I would like to add to Nicola's excellent answer. Yes, you must never return a dangling reference (e.g., reference to a local variable), however, there are three useful ways to improve performance in those cases:
Return-value optimisation (RVO): You return by value, but eliminate copying by having only one return
statement, which creates the return value on the spot. Here's an example of RVO being used: http://stackoverflow.com/questions/275733/c-string#275747
Named return-value optimisation (NRVO): You return by value, and declare the return value variable first, at the top of the function. All return
statements return that variable. With compilers that support NRVO, that variable is allocated in the return-value slot, and does not get copied upon return. e.g.,
string
foobar()
{
string result;
// fill in "result"
return result;
}
Use a shared_ptr
or the like as the return type; this necessitates creating your object on the heap, rather than the stack. This prevents dangling-reference problems while still not requiring the whole object to be copied, just the smart pointer.
By the way, I can't take credit for the information about RVO and NRVO; they come straight out of Scott Meyers's More Effective C++. Since I don't have the book with me at the moment, any errors in my description are my doing, not Scott's. :-)
I asked an almost identical question a few weeks ago:
http://stackoverflow.com/questions/134731/returning-a-const-reference-to-an-object-instead-of-a-copy