tags:

views:

1003

answers:

6

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?

+5  A: 

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.

anon
Ah, I was avoiding the method described in the 2nd snippet because I assumed it produced a stack assigned memory value... Previously I was using this, and getting SIGSEGV errors; after changing to returning pointers or references, the seg faults went away...
nbolton
By second method, I mean the method: Foobar helloWorld()
nbolton
The value return requires aworking copy constructor and destructor - if you were getting memory access errors, one of these (or both) is probably not implemented correctly.
anon
+1. The by-value approach in Neil's 2nd snippet is by far the clearest and least error prone, provided Foobar is a value-like type and not too enormous.
j_random_hacker
+1  A: 

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?

Charlie Martin
Thanks, so my code is valid yes? I am returning this value; please see update #1.
nbolton
+2  A: 

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.

Uri
Hmm, so you would recommend [in general] that I return pointers because they're more robust?
nbolton
It's ok to return references in situations where they are appropriate, like operators, so you will often see a return by reference.
Uri
+2  A: 

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!).

Scott Langham
nbolton
acidzombie24
I'm pretty sure I read somewhere that this works. I'm afraid I can't remember where. It does seem to compile for me using MS Visual Studio 2008.
Scott Langham
class MyType{public: MyType(int v) : j(v) {} int j;};int _tmain(int argc, _TCHAR* argv[]){ MyType
Scott Langham
Scott: Yes, this is a known MSVC bug.
Scott Langham
+1, but please mention that the temporary bound to your const ref in the 1st snippet will be destroyed at the end of the function, meaning that it's useless to return a reference to it -- any code that uses the reference will likely crash.
j_random_hacker
@Scott: Thanks! :)
j_random_hacker
+2  A: 
acidzombie24
+1  A: 

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;
}
Fred Larson