¿Es correcto el siguiente código (func1 ()) si tiene que devolver i? Recuerdo haber leído en alguna parte que hay un problema al devolver la referencia a una variable local. ¿En qué se diferencia de func2 ()?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int& i = * new int;
Respuestas:
Este fragmento de código:
no funcionará porque está devolviendo un alias (una referencia) a un objeto con una duración limitada al alcance de la llamada a la función. Eso significa que una vez que
func1()
regresa,int i
muere, lo que hace que la referencia devuelta por la función no tenga valor porque ahora se refiere a un objeto que no existe.La segunda versión funciona porque la variable se asigna en la tienda gratuita, que no está vinculada a la duración de la llamada a la función. Sin embargo, usted es responsable
delete
de realizar las asignacionesint
.Normalmente, envolvería el puntero en alguna clase RAII y / o una función de fábrica para no tener que
delete
hacerlo usted mismo.En cualquier caso, puede devolver el valor en sí (aunque me doy cuenta de que el ejemplo que proporcionó probablemente fue artificial):
Tenga en cuenta que está perfectamente bien devolver objetos grandes de la misma manera que
func3()
devuelve valores primitivos porque casi todos los compiladores implementan actualmente alguna forma de optimización del valor de retorno :Curiosamente, vincular un temporal a una referencia constante es C ++ perfectamente legal .
fuente
int* p = func2(); delete p;
Ahora, cuando eliminaste 'p', ¿significa que la memoria asignada "dentro" de lafunc2()
definición de la función también se eliminó?func2()
y se liberó afuera en la siguiente línea. Sin embargo, es una forma bastante propensa a errores de manejar la memoria, como dije, usaría alguna variante de RAII en su lugar. Por cierto, parece que estás aprendiendo C ++. Recomiendo elegir un buen libro de introducción a C ++ para aprender. Además, para referencia futura si tiene una pregunta, siempre puede publicar la pregunta en Stack Overflow. Los comentarios no están destinados a hacer preguntas totalmente nuevas.Una variable local es la memoria en la pila, esa memoria no se invalida automáticamente cuando se sale del alcance. Desde una función anidada más profundamente (más arriba en la pila en la memoria), es perfectamente seguro acceder a esta memoria.
Sin embargo, una vez que la función regresa y termina, las cosas se ponen peligrosas. Por lo general, la memoria no se elimina ni se sobrescribe cuando regresa, lo que significa que la memoria en esa dirección todavía contiene sus datos; el puntero parece válido.
Hasta que otra función acumula la pila y la sobrescribe. Esta es la razón por la que esto puede funcionar por un tiempo, y luego dejar de funcionar repentinamente después de que un conjunto de funciones particularmente anidado profundamente, o una función con un tamaño realmente grande o muchos objetos locales, alcance esa memoria de pila nuevamente.
Incluso puede suceder que vuelva a llegar a la misma parte del programa y sobrescriba su antigua variable de función local con la nueva variable de función. Todo esto es muy peligroso y debería desalentarse en gran medida. ¡No use punteros a objetos locales!
fuente
Algo bueno para recordar son estas reglas simples, y se aplican tanto a parámetros como a tipos de retorno ...
Hay un momento y un lugar para cada uno, así que asegúrese de conocerlos. Las variables locales, como ha mostrado aquí, son solo eso, limitadas al tiempo que están vivas localmente en el ámbito de la función. En su ejemplo, tener un tipo de
int*
devolución y devolución&i
habría sido igualmente incorrecto. Estaría mejor en ese caso haciendo esto ...Hacerlo cambiaría directamente el valor de su parámetro pasado. Considerando que este código ...
no lo haría. Simplemente cambiaría el valor de
oValue
local a la llamada a la función. La razón de esto es porque en realidad solo cambiaría una copia "local" deoValue
, y no aoValue
sí mismo.fuente