tags:

views:

1483

answers:

9

This is a little subjective I think; I'm not sure if the opinion will be unanimous (I've seen a lot of code snippets where references are returned).

According to a comment toward this question I just asked, regarding initializing references, returning a reference can be evil because, [as I understand] it makes it easier to miss deleting it, which can lead to memory leaks.

This worrys me, as I have followed examples (unless I'm imagining things) and done this in a fair few places... Have I misunderstood? Is it evil? If so, just how evil?

I feel that because of my mixed bag of pointers and references, combined with the fact that I'm new to C++, and total confusion over what to use when, my applications must be memory leak hell...

Also, I understand that using smart/shared pointers is generally accepted as the best way to avoid memory leaks, so thanks in advance for your tips ;)

+5  A: 

It's not evil. Like many things in C++, it's good if used correctly, but there are many pitfalls you should be aware of when using it (like returning a reference to a local variable).

There are good things that can be achieved with it (like map[name] = "hello world")

Mehrdad Afshari
+11  A: 

No. No, no, a thousand times no.

What is evil is making a reference to a dynamically allocated object and losing the original pointer. When you new an object you assume an obligation to have a guaranteed delete.

But have a look at, eg, operator<<: that must return a reference, or

cout << "foo" << "bar" << "bletch" << endl ;

won't work.

Charlie Martin
Oh dear, a down vote :S Are there people who believe "yes yes yes" and "no no no"? Now I'm even more confused! lol
nbolton
There are a lot of nitwits out there.
anon
Why the heck was this voted down??
Fred Larson
You guys are welcome to upvote me. It seems like I've been getting a lot of random downvotes; I may have an ankle-biter.
Charlie Martin
Nitwits? I downvoted because this neither answers the question (in which OP has made clear he knows the need for deletion) nor addresses the legitimate fear that returning a reference to a freestore object can lead to confusion. Sigh.
See GMan's post for a mostly adequate answer.
Nitwit. the practice of returning a reference object is *not* evil. Ergo no. The fear he expresses is a correct fear, as I point out in the second graf.
Charlie Martin
You actually didnt. But this is not worth my time.
@ Iraimbilanja - why did you not accompany your downvote with the explanation you have just given?
anon
It would appear the disagreement is pretty general.
Charlie Martin
what the hell, I just maxed out for the day anyway.
Charlie Martin
+2  A: 

Not only is it not evil, it is sometimes essential. For example, it would be impossible to implement the [] operator of std::vector without using a reference return value.

anon
Ah, yes of course; I think this is why I started using it; as when I first implemented the subscript operator [] I realized the use of references. I'm lead to believe that this is the de facto.
nbolton
+12  A: 

Do you mean:

int& getInt(void)
{
    int i;
    return i;
}

That is all sorts of evil. The stack-allocated i will go away and you are referring to nothing. This is semi-evil:

int& getInt(void)
{
    int *i = new int;
    return *i;
}

Because now the client has to eventually do the strange:

int& myInt = getInt(); // note the &.
int badInt = getInt(); // the & will be easy to miss (source of problems).
delete &myInt; // must delete.
delete &badInt; // won't work. badInt was a copy of the allocated int, which
                // is now lost forever

I think the best way to do something like that is just:

int *getInt(void)
{
    return new int;
}

And now the client stores a pointer:

int *myInt = getInt(); // has to be a pointer
int& weirdInt = *getInt(); // but this works too if you really want.
delete myInt; // being a pointer, this is easy to do.
delete &weirdInt; // works.

Now for members of classes, & is powerful, such as operator chaining (cout's <<), or operator[].

GMan
pointers are bad.... use share pointers
Of course. This was an example.
GMan
+1  A: 

There are two cases:

  • const reference --good idea, sometimes, especially for heavy objects or proxy classes, compiler optimization

  • non-const reference --bad idea, sometimes, breaks encapsulations

Both share same issue -- can potentially point to destroyed object...

I would recommend using smart pointers for many situations where you require to return a reference/pointer.

Also, note the following:

There is a formal rule - the C++ Standard (section 13.3.3.1.4 if you are interested) states that a temporary can only be bound to a const reference - if you try to use a non-const reference the compiler must flag this as an error.

non-const ref doesnt necessarily break encapsulation. consider vector::operator[]
that's a very special case... that's why I said sometimes, though I should really claim MOST OF THE TIME :)
So, you're saying that the normal subscript operator implementation a necessary evil? I neither disagree or agree with this; as I am none the wiser.
nbolton
I don't say that, but it can be evil if misused :))) vector::at should be used whenever possible....
eh? vector::at also returns a nonconst ref.
+3  A: 

"returning a reference is evil because, simply [as I understand] it makes it easier to miss deleting it"

Not true. Returning a reference does not imply ownership semantics. That is, just because you do this:

Value& v = thing->getTheValue();

...does not mean you now own the memory referred to by v;

However, this is horrible code:

int& getTheValue()
{
   return *new int;
}

If you are doing something like this because "you don't require a pointer on that instance" then: 1) just dereference the pointer if you need a reference, and 2) you will eventually need the pointer, because you have to match a new with a delete, and you need a pointer to call delete.

John Dibling
+1  A: 

You should return a reference to an existing object that isn't going away immediately, and where you don't intend any transfer of ownership.

Never return a reference to a local variable or some such, because it won't be there to be referenced.

You can return a temporary as a const reference. A temporary is something like a + b, where the compiler creates a temporary object that will normally go away at the end of the expression. You might implement operator+ like that.

You can return a reference to something independent of the function, which you don't expect the calling function to take the responsibility for deleting. This is the case for the typical operator[] function.

If you are creating something, you should return either a value or a pointer (regular or smart). You can return a value freely, since it's going into a variable or expression in the calling function. Never return a pointer to a local variable, since it will go away.

David Thornley
Excellent answer but for "You can return a temporary as a const reference." The following code will compile but probably crash because the temporary is destroyed at the end of the return statement: "int const } void main() { int const ++r; }"
j_random_hacker
@j_random_hacker: C++ has some strange rules for references to temporaries, where the temporary lifetime might be extended. I'm sorry I don't understand it well enough to know if it covers your case.
Mark Ransom
@Mark: Yes, it does have some strange rules. A temporary's lifetime can only be extended by initialising a const reference (that is not a class member) with it; it then lives until the ref goes out of scope. Sadly, returning a const ref is *not* covered. Returning a temp by value is safe however.
j_random_hacker
See the C++ Standard, 12.2, paragraph 5. Also see Herb Sutter's stray Guru of the Week at http://herbsutter.wordpress.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/.
David Thornley
j_random_hacker
j_random_hacker
A: 

Function as lvalue (aka, returning of non-const references) should be removed from C++. It's terribly unintuitive. Scott Meyers wanted a min() with this behavior.

min(a,b) = 0;  // What???

which isn't really an improvement on

setmin (a, b, 0);

The latter even makes more sense.

I realize that function as lvalue is important for C++ style streams, but it's worth pointing out that C++ style streams are terrible. I'm not the only one that thinks this... as I recall Alexandrescu had a large article on how to do better, and I believe boost has also tried to create a better type safe I/O method.

Dan Olson
Sure it's dangerous, and there should be better compiler error checking, but without it some useful constructs could not be done, e.g. operator[]() in std::map.
j_random_hacker
A: 

I ran into a real problem where it was indeed evil. Essentially a developer returned a reference to an object in a vector. That was Bad!!!

The full details I wrote about in Janurary: http://developer-resource.blogspot.com/2009/01/pros-and-cons-of-returing-references.html

Hope that helps, @developresource

developresource
If you need to modify the original value in the calling code, then you *need* to return a ref. And that is in fact no more and no less dangerous than returning an iterator to a vector -- both are invalidated if elements are added to or removed from the vector.
j_random_hacker