What is the best practice for returning references from class methods. Is it the case that basic types you want to return without a reference whereas class objects you want to r
I'll assume that by class method you mean member function. And that by "return by reference" you mean "return reference to member data". This is mainly as opposed to returning a reference to local, which is clearly wrong.
When should you return a reference to member data, and when the data itself ?
By default, you should be returning the data itself (aka "by value"). This avoids several problems with returning a reference:
Users storing the reference and becoming dependant on the lifetime of your members, without considering how long the containing object (your object) will live. Leads to dangling pointers.
User code becoming dependant on the exact return type. For example, you use a vector<T>
for implementation (and that's what your getter returns). User code like "vector<T> foo = obj.getItems()
" appears. Then you change your implementation (and getter) to use a deque<T>
-- user code breaks. If you had been returning by value, you could simply make the getter create a local vector, copy the data over from the member deque, and return the result. Quite reasonable for small-sized collections. [*]
So when should you return a reference instead?
Image
) or non-copyable (boost::signal
). But, as always, you can instead opt for the more OOP pattern of having your class do stuff rather than have stuff hanging from it. In the Image
case, you can provide a drawCircle
member function, rather than returning Image&
and having your users draw a circle on it.vector<T>::operator[]
returns a reference to T because that's what I want to get at: my exact object, not a copy of it.[*] There is a better way to ensure future-proof code. Rather than returning a vector (by ref of by value) return a pair of iterators to your vector -- a beginning and an ending one. This lets your users do everything they normally do with a deque or a vector, but independent of the actual implementation. Boost provides boost::iterator_pair
for this purpose. As a perk, it also has operator[] overloaded, so you can even do "int i = obj.getItems()[5]
" rather than "int i = obj.getItems().begin()[5]
".
This solution is generalizable to any situation which allows you to treat types generically. For example, if you keep a Dog
member but your users only need to know it's an Animal
(because they only call eat()
and sleep()
), return an Animal reference/pointer to a freestore-allocated copy of your dog. Then when you decide dogs are weaklings and you really need a wolf for the implementation, user code won't break.
This sort of information-hiding does more than ensure future-compatibility. It also helps keep your design clean.