views:

94

answers:

5

Is this the right way to return an object from a function?

Car getCar(string model, int year) {
   Car c(model, year);
   return c;
}

void displayCar(Car &car) {
   cout << car.getModel() << ", " << car.getYear() << endl;
}

displayCar(getCar("Honda", 1999));

I'm getting an error, "taking address of temporary". Should I use this way:

Car &getCar(string model, int year) {
   Car c(model, year);
   return c;
}
+1  A: 

It is not safe to return a local variable's reference from a function.

So yes this is correct:

Car getCar(string model, int year) {
   Car c(model, year);
   return c;
}
Brian R. Bondy
Hmm, I need something like a factory function which will create an object and return it back.
pocoa
Many (most?) compilers optimize `return Car(model, year)` so that no additional copy needs to be made, so I'd get rid of the explicit local variable.
Steven Sudit
@Steven: Many (most?) compilers implement named return value optimization (NRVO) as well, so there's generally no difference.
James McNellis
@pocoa: You could also use dynamic memory for all of this by allocating a `new` instance and returning by pointer. I would recommend using the appropriate sort of smart pointer, to avoid leaks.
Steven Sudit
@James: You may be right. Last I checked, named values were less likely to be optimized.
Steven Sudit
@Steven: most modern compilers can even optimize away the copy operation in the function as-is (NRVO), but I agree that it is a safer baet to just return a temporary.
Nemanja Trifunovic
@Nemanja: Actually, I'm saying you shouldn't return a *named* temporary. It used to be the case that we could count on compilers performing RVO on unnamed temporaries but not named ones. According to James, this is outdated, and now compilers will optimize it either way. If so, great.
Steven Sudit
+8  A: 

getCar returns a Car by value, which is correct.

You cannot pass that return value, which is a temporary object, into displayCar, because displayCar takes a Car&. You cannot bind a temporary to a non-const reference. You should change displayCar to take a const reference:

void displayCar(const Car& car) { }

Or, you can store the temporary in a local variable:

Car c = getCar("Honda", 1999);
displayCar(c);

But, it's better to have displayCar take a const reference since it doesn't modify the object.

Do not return a reference to the local Car variable.

James McNellis
+6  A: 

Your problem is:

void displayCar(Car &car) {
   cout << car.getModel() << ", " << car.getYear() << endl;
}

you should use a const reference:

void displayCar( const Car & car ) {
   cout << car.getModel() << ", " << car.getYear() << endl;
}

This function:

Car getCar(string model, int year) {
   Car c(model, year);
   return c;
}

is OK as it stands, but all it is doing is what the constructor does, so it is redundant. Passing a value back, rather than a reference, is the right thing to do for this type of function, however, The model parameter should be passed by const reference:

Car getCar( const string & model, int year) {

In general, for class types like string or Car, your default choice for a parameter should always be a const reference.

anon
A: 

Even better:

Car getCar(string model, int year) { 
      return Car(model, year);  
}
Nemanja Trifunovic
Exactly what I meant by "copy operations" in my answer. Although currently this is the standard solution it is much more an expensive operation than just returning an address.
themoondothshine
@themoondothshine: Most compilers (all I know of) will perform RVO here, so it is a really cheap operation.
Nemanja Trifunovic
+1  A: 

Yes, it is definitely not safe to return a reference or a pointer to a temporary object. When it expires (ie, when the function getCar exits), you'll left with what is technical known as a "dangling pointer".

However, if you're keen on reducing copy operations on an object, you should check out C++0x's "Move semantics". It is a relatively new concept, but I'm sure it'll become main-stream soon enough. GCC 4.4 upwards supports C++0x (use the compiler option -std=c++0x to enable).

themoondothshine