2009-07-05 5 views
5

En este ejemplo, ¿por qué está bien devolver una variable de pila? Cuando devuelve t(), ¿por qué no devuelve la basura, ya que el puntero de la pila se ha incrementado?devolver la variable de pila de C++

#include <<string>> 
#include <<vector>> 
#include <<iostream>> 

using namespace std; 

class X{ 
public: 

    X() { cout << "constructor" << endl; } 

    ~X() { cout << "destructor" << endl; } 

}; 

vector <X> t() 
{ 
    cout << "t() start" << endl; 

    vector<X> my_x; 

    int i = 0; 

    printf("t: %x %x %x\n", t, &my_x, &i); 

    my\_x.push\_back(X()); my\_x.push\_back(X()); my\_x.push\_back(X()); 

    cout << "t() done" << endl; 

    return my_x; 
} 

int main() 
{ 

    cout << "main start" << endl; 

    vector <X> g = t(); 


    printf("main: %x\n", &g); 

    return 0; 

} 

salida:

./a.out 
main start 
t() start 
t: 8048984 bfeb66d0 bfeb667c 
constructor 
destructor 
constructor 
destructor 
destructor 
constructor 
destructor 
destructor 
destructor 
t() done 
main: bfeb66d0 
destructor 
destructor 
destructor 
+2

Es peligroso para devolver una referencia ** ** a una variable en la pila ya que podría terminar con la basura. De lo contrario, se construirá una copia y se le entregará a la persona que llama. –

Respuesta

5

Dado que los parámetros se pasan por valor. Se hace una copia. Entonces, lo que se devuelve no es el valor en la pila, sino una copia.

+0

En realidad, una copia no se realiza gracias a un RVO con nombre, como dice smink y como lo demuestra el rastreo (la dirección de my_x en la función t es igual a la dirección de g en la función main). Pero sí, el resultado es como si se hubiera hecho una copia. –

+0

Es cierto, pero incluso sin esa optimización, su código sería válido, porque el valor se copia, por lo que lo que se devuelve no es una referencia al objeto que ya no es válido declarado en la función. – jalf

19

Básicamente cuando devuelve la variable de pila my_xsería llamando al constructor de copia para crear una nueva copia de la variable. Esto no es cierto, en este caso, gracias al todo poderoso compilador.

El compilador utiliza un truco conocido como retorno por la optimización valor haciendo que la variable my_x realmente se están construyendo en el lugar de la memoria asignada para la g en el método main. Es por eso que ve la misma dirección bfeb66d0 imprimiéndose. Esto evita la asignación de memoria y la construcción de copias.

A veces esto no es del todo posible debido a la complejidad del código y luego el compilador se restablece al comportamiento predeterminado, creando una copia del objeto.

+0

RTO es un detalle de implementación. Pero una buena. – nos

0

Bueno, se devuelve una copia, la única construcción que no puede devolver es una matriz estática. Entonces no puede decir esto ...

int[] retArray() 
{ 
    int arr[101]; 

    return arr; 
} 
0

El compilador está optimizado para manejar el retorno de "variables de pila" sin llamar al constructor de copia. Lo único que debe saber es que esa asignación de memoria está dentro del alcance tanto de la función que la asignó en la pila como de la función a la que se devuelve el objeto.

NO llama al constructor de copia ni lo asigna dos veces.

Puede haber algunos casos especiales y, por supuesto, depende del compilador; por ejemplo, las primitivas pueden copiarse, pero en general, los objetos asignados en la pila no se copian al devolverlos.

Ejemplo:

struct Test { 

}; 

Test getTest() { 
    Test t; 
    std::cout << &t << std::endl;  // 0xbfeea75f 
    return t; 
} 


int main(int argc, char *argv[]) 
{ 
    Test t = getTest(); 
    std::cout << &t << std::endl;  // also 0xbfeea75f 
} 
Cuestiones relacionadas