views:

168

answers:

5

In a non-template class, is there any reason to prefer function return signatures in the form const <type>& foo(); versus <type> foo();? Where <type> is an intrinsic type. What about if <type> is a class/struct object?

Also interested in whether or not the function being const makes a difference: const <type>& foo() const; to <type> foo() const;

E.g. in a non-template class, non-template function:

const int& foo() const { return member_variable_; }

Versus

int foo() const { return member_variable_; }
A: 

If you need to return a value, you MUST return a value - a const reference is not an acceptable substitute. But I suspect you are asking about something like this:

struct A {
   X x;
    ...
   X f1() { return x; }
   const X & f2() { return x; }
};

I've never come up with a foolproof guideline for this.

anon
@Neil: really interested more in the case of intrinsic types, in your example X would be an integer. (for what it is worth I prefer to return by value)
ceretullis
I think that, with `auto`, it becomes increasingly dangerous to return by reference. Now something like `auto x = a.f2()` will result in `x` quietly becoming a reference, and if `a` gets destroyed before `x` (which is quite possible if it's actually a smart pointer), we get a dangling reference. IMO, unless the intent is to return a reference (which is better highlighted by returning a [possibly smart] pointer), just return by value, and let RVO kick in.
Pavel Minaev
Oh yes, also, with move semantics in C++0x, the perf hit for return-by-value is going to be negligible for any type with a move constructor (which covers all standard types, and will certainly be best practice to define one for any expensive-to-copy user-defined types).
Pavel Minaev
@Pavel I almost always return values myself, but occasionally find it a bit hard to justify - your points are good ones, and I agree that "always return a value" is a good (and simple) rule.
anon
@ceretullis For the built-in types I can't see any possible justification for not returning values - there are no efficiency issues in doing so (rather the reverse, if anything).
anon
I don't think RVO would kick in for returning a member variable from a member function; as I understand it, you couldn't specify where you would like the return placed as it is part of a larger object (without a lot of inlining and rewriting by the compiler, I guess)
Todd Gardner
What Todd says - if X is some chunking great struct, and your hypothetical function has the choice of returning the member x, or a const reference to it, then no amount of RVO or move constructor is going to save you from the fact that returning by value requires a copy, and returning by reference (or pointer) doesn't. If the caller doesn't want the value to change or disappear under him then he can take a copy himself (although Pavel's first point is interesting, and not something I'd previously considered - it might not be so easy to take a copy any more).
Steve Jessop
@Neil: I actually already knew the answer before I asked ;) just playing the SO game... but actually I'm glad I asked because some of the comments are really enlightening (like @Pavel's comment about auto)
ceretullis
@Todd: yes, and move semantics won't help you in that case, either, obviously. On the other hand, another argument against returning a member by reference is that it exposes your implementation in a sense that you cannot change it later without breaking clients (and it'll be an API break, as client can e.g. bind the returned const reference to a const reference field in his own class; if you later start returning by value, he'll bind to a temporary that promptly goes out of scope).
Pavel Minaev
A: 

It all depends on what exactly you want to do.

If you want to return a reference to an object to be used by the user code, then :

<type>& foo()  { ... }

If you want to return a reference to an object but in read-only way, allowing only access to const functions of this object type, then:

const <type>& foo() { ... }

If you want to return a reference to an object to be used by the user code, even if the class instance is used in read only (as const) then:

<type>& foo() const { ... }

If you want ot return a reference to an object but in read-only way, allowing only access to const functions of this object type, and event if the class instance is used in read only (as const) then :

const <type>& foo() const { ... }

Just to add a warning : don't return references to function's variables, they are not alive out of the function...

Klaim
I have to say I doisagree very strongly with "That said, a good practice for this kind of function (but not in all cases)..." - it is good practice in only a very few cases - operator[] for containers is about the only example I can think of.
anon
Well, I'll remove this recomandation as I don't feel experienced enough, but I have to say I use often accessor-like member function that match this scheme, using the const-correctness to make read-only access of a whole system possible without breaking it by using non-const member functions. That said, I might not be experienced enough to see the problem with that.
Klaim
Just because you have a non-const instance of (or reference to) a class does not mean that you should have unrestricted access to its data members. If you rely solely on the const-ness of the instance you are accessing, you might as well do away with member functions and use plain structs.
anon
A: 
const <type>& foo();

You might have a resource like container of elements in your class and foo() returns specific element, if you know that the resources will be available long enough you might return const reference to element in container that way you avoid unnecessary allocation/copy of data. It might be const or not, depends on how you deal with the data, if you don't want the data to be modified via the reference returned by foo() then make it const. Maybe you have a case where you want to modify resource and some extra work needs to be done, you would make that non const. You can have both in your api user will choose base on usecase.

<type> foo();

Returns a new copy of resource <type>. That means a copy is made. This is good for simple data or where values might be shared and you want to make sure that each instance of <type> is separate - non-shared like some string or int.

stefanB
A: 

If the type is an intrinsic type, passing around const refs will not improve performance, and may degrade it, as well as being less safe; it is better to prefer passing and returning by value. I am not much of an ASM guy but as I understand it, by reference return means the value couldn't be stored in a register, as it needs an address for the return, and thereby can disable some otherwise useful optimizations; I am not positive on this though.

If it is a class or struct, it depends on lifetime of the value; if it is local to the function then it cannot be returned, otherwise, if it is a class member, I prefer the const type& return as it can offer better performance by avoiding copy-constructors. (opinions differ, as the by value is considered safer). It also saves you from having to implement copy-constructors or using the potentially evil default, which is nice.

Todd Gardner
+3  A: 

For primitive types, simply return by value. There is no reason to return a primitive by const reference.

For non-primitive types, it depends.

If the value returned is a local variable of the function, then you must return by value. Otherwise, the variable will be destroyed before the caller can consume the returned reference.

If the value returned is a class data member, then you have a choice.

Return by const reference avoids copies, which may be a performance advantage. However, it ties your interface to the implementation, i.e. the data member and return value must be the same type. It is also less safe because the caller can retain the reference longer than the object's lifetime, such as:

const X& x = y->foo();
delete y;
// use x, oops!

Return by value incurs one or two copies, depending on if you can take advantage of return value optimizations (which is likely for simple get() methods such as this). In addition, copies of objects using default copy constructors may be copied more efficiently (think: the compiler can simply memcpy the data).

Recommendation: start with return by value, and switch to return by const reference only after determining that that call/copy is known to be a performance issue.

Finally, another alternative is to return by parameter, which can be useful for more complex objects (e.g., string):

void foo(X& return_val) { return_val = member_variable_; }

or:

void foo(X* return_val) {
    assert(return_val != 0);
    *return_val = member_variable_;
}
Jason Govig
'copies of objects using default ... memcpy' => not quite. The standard allows compiler to elide the copy, in what is called Return Value Optimization. `T f() { T tmp; /* operate */ return tmp; }` what the compiler is allowed to do is create the `tmp` variable in the memory allocated for the return value, and as such avoid copying the variable in the return statement. Compilers will not `memcpy` objects from one position to another.
David Rodríguez - dribeas
My memcpy comment was not referring to Return Value Optimization, but to direct copies of POD objects vs. indirect copies. See http://docs.sun.com/app/docs/doc/820-7599/bkahu?a=view for example.
Jason Govig