Pregunta

Estoy comenzando de nuevo con c ++ y estaba pensando en el alcance de las variables. Si tengo una variable dentro de una función y luego devuelvo esa variable, la variable no estará `` muerta '' cuando se devuelve porque el alcance en el que estaba ha terminado?

He intentado esto con una función que devuelve una cadena y funcionó. ¿Alguien puede explicar esto? O al menos indíqueme algún lugar que pueda explicarme esto, por favor.

Gracias

¿Fue útil?

Solución

  

Cuando la función termina, el   ocurren los siguientes pasos:

     
      
  • El valor de retorno de la función es   copiado en el marcador de posición que estaba   poner en la pila para este propósito.

  •   
  • Todo después del marco de la pila   el puntero está desplegado. Esto destruye   todas las variables y argumentos locales.

  •   
  • El valor de retorno se saca del   apilar y se asigna como el valor   de la función. Si el valor de la   la función no está asignada a nada,   no se realiza ninguna asignación, y el   el valor se pierde.

  •   
  • La dirección de la próxima instrucción   ejecutar se saca de la pila,   y la CPU reanuda la ejecución en   esa instrucción.

  •   

La pila y el montón

Otros consejos

Cuando devuelve un valor, se realiza una copia. El alcance de la variable local finaliza, pero se realiza una copia y se devuelve a la función de llamada. Ejemplo:

int funcB() {
  int j = 12;
  return j;
}

void A() {
  int i;
  i = funcB();
}

El valor de j (12) se copia y se devuelve a i para que reciba el valor de 12.

Realmente depende de qué tipo de variable está devolviendo. Si devuelve una primitiva, se devuelve por copia, no por referencia, por lo que el valor se copia en la parte superior de la pila (o, más a menudo se coloca en un registro) donde la función de llamada puede obtenerlo. Si asigna un objeto o memoria en el montón y devuelve un puntero, entonces no muere porque está en el montón, no en la pila. Sin embargo, si asigna algo en la pila y lo devuelve, sería algo malo. Por ejemplo, cualquiera de estos sería muy malo:

int *myBadAddingFunction(int a, int b)
{
    int result;

    result = a + b;
    return &result; // this is very bad and the result is undefined
}

char *myOtherBadFunction()
{
    char myString[256];

    strcpy(myString, "This is my string!");
    return myString; // also allocated on the stack, also bad
}

Solo por un poco más de una explicación orientada al modelo de memoria: cuando se llama a una función, se crea un espacio temporal para que la función coloque sus variables locales, denominadas marco . Cuando la función (llamado) devuelve su valor, coloca el valor de retorno en el marco de la función que lo llamó (llamador), y luego se destruye el marco llamado.

El marco "se destruye" parte es por qué no puede devolver punteros o referencias a variables locales desde funciones. Un puntero es efectivamente una ubicación de memoria, por lo que devolver la ubicación de memoria de una variable local (por definición: una variable dentro del marco) se vuelve incorrecta una vez que se destruye el marco. Dado que el marco de llamada se destruye tan pronto como devuelve su valor, cualquier puntero o referencia a una variable local es inmediatamente incorrecto.

La variable local se copia al valor de retorno. Los constructores de copia se llaman para clases no triviales.

Si devuelve un puntero o una referencia a una variable local, tendrá problemas --- tal como lo sugirió su intuición.

Esto depende del tipo del artículo devuelto. Si regresa por valor, se realiza una nueva copia de la variable para regresar a la persona que llama. Creo que no necesita preocuparse por la vida útil de los objetos, pero puede que tenga que preocuparse por los costos de copiar objetos (pero no optimice prematuramente; la corrección es mucho más importante):

std::string someFunc( std::string& const s)
{
    return s + "copy";
}

Si la función está devolviendo una referencia, debe tener cuidado con lo que está devolviendo porque su vida útil debe extenderse más allá de la vida útil de la función y la persona que llama no necesariamente podrá eliminar si usa new para crear el objeto:

std::string& someFunc2( std::string const& s)
{
    return s + "reference to a copy";   // this is bad - the temp object created will 
                                        //  be destroyed after the expression the 
                                        //  function call is in finishes.
                                        //  Some, but not all, compilers will warn 
                                        //  about this.
}

Por supuesto, los punteros que regresan tendrán consideraciones similares de por vida.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top