2010-04-30 21 views
40

Mire el siguiente código. Sé que no devuelve la dirección de la variable local, pero ¿por qué todavía funciona y asigna la variable i en main() a '6'? ¿Cómo solo devuelve el valor si la variable se eliminó de la memoria de la pila?Devolución de una referencia a una variable local o temporal

#include <iostream> 

int& foo() 
{ 
    int i = 6; 
    std::cout << &i << std::endl; //Prints the address of i before return 
    return i; 
} 

int main() 
{ 
    int i = foo(); 
    std::cout << i << std::endl; //Prints the value 
    std::cout << &i << std::endl; //Prints the address of i after return 
} 
+19

Tienes suerte. No lo hagas –

+3

Puede encontrar esto útil: http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope – letsc

+0

Creo que algo de suerte está en el hecho de que es inalterado en foo() (que permite a los compiladores colocar en texto o en algún lugar de larga vida en lugar de pila) – mho

Respuesta

22

Tienes suerte. Al regresar de la función, no se limpia inmediatamente el marco de pila que acaba de salir.

Por cierto, ¿cómo confirmaste que obtuviste un 6? La expresión std::cout << &i ... imprime la dirección de i, no su valor.

+3

el 6 sale cuando lo imprime en main(). –

+2

@San: Bueno, ahora sí que Dave18 editó la pregunta. –

+1

Lo siento, debo haber leído la pregunta después de esto :) –

1

Mientras que su función devuelve un número entero por referencia, se asigna inmediatamente a la variable local 'i' en main(). Eso significa que la memoria de pila asignada para foo() debe persistir el tiempo suficiente para la asignación de retorno. Si bien es mala forma, esto generalmente funciona. Si hubiera tratado de mantener una referencia

int &i = foo(); 

, sería mucho más probable que falle.

3

Devolver referencia o puntero a una variable local es un comportamiento indefinido. Comportamiento no definido significa que el estándar deja la decisión al compilador. Eso significa que el comportamiento indefinido a veces funciona bien y sometimes it doesn't.

+4

Y las posibilidades de que no funcione bien dependen de la importancia de las personas que miran la demostración. – KeithB

2

La dirección de i nunca va a cambiar en main(), pero el valor que contiene. Está tomando la referencia de una variable local y usándola después de que la referencia haya caído fuera del alcance. (Advertencia de lenguaje impreciso) El valor 6 está en la pila. Como no hizo nada con la pila después de poner allí el 6, la referencia a ella aún contendrá el mismo valor. Entonces, como otros han dicho, tuvieron suerte.

para ver cuán afortunada, intente ejecutar el código que utiliza la pila después de llamar foo():

#include <iostream> 
#include <ctime> 
#include <numeric> 

int& foo() 
{ 
    int i = 6; 
    std::cout << &i << " = " << i << std::endl; //Prints the address of i before return 
    return i; 
} 

long post_foo(int f) 
{ 
    srand((unsigned)time(0)); 

    long vals[10] = {0}; 
    size_t num_vals = sizeof(vals)/sizeof(vals[0]); 
    for(size_t i = 0; i < num_vals; ++i) 
    { 
     int r = (rand()%2)+1; 
     vals[i] = (i+f)*r; 
    } 

    long accum = std::accumulate(vals, &vals[num_vals], 0); 
    return accum * 2; 
} 

int main() 
{ 
    int &i = foo(); 
// std::cout << "post_foo() = " << post_foo(i) << std::endl; 
    std::cout << &i << " = " << i << std::endl; 
} 

Cuando me encontré con esto con el post_foo() llamada comentado, 6 todavía estaba en la pila y la salida era:

002CF6C8 = 6 
002CF6C8 = 6 

... pero cuando un-comentó la llamada a post_foo() y corrió otra vez, 6 había ido de largo:

001FFD38 = 6 
post_foo() = 310 
001FFD38 = 258923464 
Cuestiones relacionadas