19
votes

I've tried to Google this issue, and I can't find anything that I see as relevant. So I must be looking for the wrong thing; none the less, I'd appreciate some advice...

Foobar &foobar = *new Foobar(someArg, anotherArg);

Is it just me or does that seem smelly?

I understand that the new keyword is designed for use with pointers (as such):

Foobar *foobar = new Foobar(someArg, anotherArg);

But what if you don't require a pointer on that instance, and you would like to use a reference instead? Or, is it the case that you don't need to explicitly initialize it (much like local variables); and if this is the case, what if I want to initialize with parameters?

The following does not work (unless I'm doing something wrong):

// the last argument is of type: int
Foobar &foobar(someArg, anotherArg);

... gives the compiler error:

initializer expression list treated as compound expression invalid initialization of non-const reference of type ‘Foobar&’ from a temporary of type ‘int’

And also this doesn't seem to work:

Foobar &foobar = Foobar(someArg, anotherArg);

... gives the compiler error:

error: invalid initialization of non-const reference of type ‘Foobar&’ from a temporary of type ‘Foobar’

Update 1:

Bare in mind that I am returning this value, so I don't want to use a local variable; I want to use a value on the heap, not the stack:

Foobar &helloWorld()
{
    Foobar &foobar = *new Foobar(someArg, anotherArg);
    foobar.HelloWorld();
    return foobar;
}

Should I just be using pointers instead, or is this completely valid?

6
It works... but as I say in my answer, that's unconventional, so no other programmer using helloWorld will expect they have to delete the returned Foobar, and it makes it very memory leak prone. - Scott Langham
You are better off returning a pointer. Or better still, see the stl::auto_pointer. Return one of those, and whatever the programmer using your function does with the result, it will be guaranteed to be deleted again without leaving a leak. - Scott Langham
Great tip for auto_ptr! :) I will start using that instead of returning references... - Nick Bolton
r3n: that is so evil. How will you ever know when to free Foobar & >:-). I'm sure you can write that so it doesnt use new. Also, if you look at c++0x you'll find the && operator. In a year when it comes out doing Foobar fooVar(someArg, anotherArg); return fooVar; is efficient. - user34537
acidzombie24: Haha, yes, I never thought about how references are misleading... Maybe I'm evil by nature; oh dear! - Nick Bolton

6 Answers

11
votes

Why do you think you need to use new and references at all? Why not:

Foobar foobar(someArg, anotherArg);

For your function - return a value:

Foobar helloWorld()
{
    Foobar foobar(someArg, anotherArg);
    foobar.HelloWorld();
    return foobar;
}

or a pointer:

Foobar * helloWorld()
{
    Foobar * foobar = new Foobar(someArg, anotherArg);
    foobar->HelloWorld();
    return foobar;
}

If you do this - the caller is responsible for deleting the allocated object at some point.

Return from a non-member function is one place where references can typically not be used sensibly, as the thing you would like to refer to usually no longer exists.

6
votes

Yes, that is smelly!

If you 'new' something, assign it to a pointer (or smart-pointer type), as it will need to be deleted again to avoid a memory leak. References aren't conventionally thought of as being things you need to delete again, so if somebody else sees that code (assigning a new'ed object to a reference), it may well confuse them.

You can do...

const Foobar &foobar = Foobar(someArg, anotherArg);

...if you really want a reference. Note that once foobar goes out of scope, the temporary object it is referencing will die. But, there's not a lot of point in writing that when you can straight-forwardly write:

Foobar foobar(someArg, anotherArg);

You probably don't actually need a reference... they're generally (but not exclusively) used for the types of method arguments. This is so that you can pass something that looks like an object, but only has the size of a pointer, and which the method can modify. The reference was introduced primarily to allow you to write a copy constructor (I won't explain that here!).

3
votes

References in C++ are really not as strong as people expect them to be, I think the confusion comes from people who are used to languages like Java and C# that don't have pointers and have references that can be reassigned and used.

A reference in C++ is generally best used as an alias for a variable, so you can simplify things like parameter passing and return values. There are very few situations where you would try to acquire a reference the way you are doing on the first line. So usually you don't need to do what it seems that you're trying to do :)

The second line is of course correct, and you could do something like return *foobar from a function that returns a reference.

2
votes

Your writing it right. But keep in mind its weird to free the ptr by doing delete &refVar; (it could be mistaken for a variable that was not created by new).

You should check out GotW for good practices passing around http://www.gotw.ca/gotw/ I dont remember which lesson it was (there was more then one) but reading through that is more valuable then anyone realize (gotchas will be less of a surprise)

You should try writing code that NEVER use pointers. I do it but once got stuck when i needed a container of BaseObj. There was no working around that. Typically i used the STL containers and have most variable alive on the stack { MyClass myVar; ... } or as a member and pass it around as needed.

Its quiet easy to remove pointers once you start passing reference instead of pointers and use stl containers instead of new. Note that i never use auto_ptr. vector, string, deque, list and map should do most of what you need. There are other containers.

1
votes

Nope, you've got it. A foo& "points to" the actual object, so if you really want a foo reference you have to dereference the foo pointer.

@Neil has a point, though -- syntactically that's how you get what you want, but why do you want it?

1
votes

I'd recommend using a smart pointer. You need to manage ownership, and a reference will not do that for you. In fact, it will obscure to the caller that there's any ownership issue at all. As Scott Langham mentioned in a comment, std::auto_ptr would work. Using shared_ptr from Boost or TR1 might be a better idea.

boost::shared_ptr<Foobar> helloWorld()
{
    boost::shared_ptr<Foobar> foobar(new Foobar(someArg, anotherArg));
    foobar->HelloWorld();
    return foobar;
}