2010-04-02 9 views
10

¿Es esta la forma correcta de devolver un objeto desde una función?Devolución de un objeto local desde una función

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)); 

Me aparece un error, "tomando la dirección de temporal". Debería usar de esta manera:

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

Respuesta

23

getCar devuelve un Car por valor, lo cual es correcto.

No puede pasar ese valor de retorno, que es un objeto temporal, en displayCar, porque displayCar toma Car&. No puede vincular una referencia temporal a una referencia no constante. Debe cambiar displayCar para tomar una referencia constante:

void displayCar(const Car& car) { } 

O bien, puede almacenar el temporal en una variable local:

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

embargo, es mejor tener displayCar tomar una referencia constante, ya que doesn no modifica el objeto

No devolver una referencia a la variable local Car.

+0

también puede almacenar el temporal sin invocar el constructor de copia (que ocurre en 'Car c = getCar (...)' usando una referencia a const: 'const Car & c = getCar (...)', si no 't necesito hacer cambios a través de 'c' más adelante. –

4

No es seguro devolver la referencia de una variable local desde una función.

Así que sí, esto es correcto:

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

Hmm, necesito algo así como una función de fábrica que creará un objeto y lo devolverá. – pocoa

+1

Muchos (¿la mayoría?) Compiladores optimizan 'devolver el automóvil (modelo, año)' para que no se necesite hacer ninguna copia adicional, así que me desharía de la variable local explícita. –

+0

@Steven: Muchos (¿la mayoría?) Compiladores implementan la optimización del valor de retorno (NRVO) también, por lo que generalmente no hay diferencia. –

8

Su problema es:

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

se debe utilizar una referencia constante:

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

Esta función:

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

está bien tal como está, pero todo lo que está haciendo es lo que hace el constructor, por lo que es redundante. El paso de un valor de nuevo, en lugar de una referencia, es lo que hay que hacer para este tipo de la función, sin embargo, los parámetros del modelo se debe pasar por referencia const:

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

En general, para los tipos de clases como cadena o automóvil, su elección predeterminada para un parámetro siempre debe ser una referencia constante.

0

Aún mejor:

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

Exactamente lo que quise decir con" operaciones de copia "en mi respuesta. Aunque actualmente esta es la solución estándar, es mucho más costosa que simplemente devolver una dirección. – themoondothshine

+1

@themoondothshine : La mayoría de los compiladores (todo lo que sé) realizarán RVO aquí, por lo que es una operación realmente barata. –

2

Sí, es definitivamente no es seguro para devolver una referencia o un puntero a un objeto temporal. Cuando caduque (es decir, cuando finalice la función getCar), se quedará con lo que se conoce como "puntero colgante".

Sin embargo, si está interesado en reducir las operaciones de copia en un objeto, debe verificar C++ 0x "Mover semántica". Es un concepto relativamente nuevo, pero estoy seguro de que se convertirá en main-stream lo suficientemente pronto. GCC 4.4 en adelante admite C++ 0x (use la opción del compilador -std=c++0x para habilitar).

Cuestiones relacionadas