Mientras leía esta explicación sobre lvalues y rvalues, estas líneas de código me llamaron la atención:
int& foo();
foo() = 42; // OK, foo() is an lvalue
Lo intenté en g ++, pero el compilador dice "referencia indefinida a foo ()". Si agrego
int foo()
{
return 2;
}
int main()
{
int& foo();
foo() = 42;
}
Se compila bien, pero ejecutarlo produce un error de segmentación . Solo la linea
int& foo();
por sí mismo se compila y se ejecuta sin problemas.
¿Qué significa este código? ¿Cómo se puede asignar un valor a una llamada de función y por qué no es un rvalue?
c++
function
return-by-reference
Sossisos
fuente
fuente
Respuestas:
La explicación asume que existe alguna implementación razonable para la
foo
cual devuelve una referencia lvalue a un valor válidoint
.Tal implementación podría ser:
Ahora, dado que
foo
devuelve una referencia lvalue, podemos asignar algo al valor de retorno, así:Esto actualizará el global
a
con el valor42
, que podemos verificar accediendo a la variable directamente o llamandofoo
nuevamente:fuente
Todas las demás respuestas declaran una estática dentro de la función. Creo que eso podría confundirte, así que mira esto:
Como
highest()
devuelve una referencia, puede asignarle un valor. Cuando se ejecute,b
se cambiará a 11. Si cambió la inicialización para quea
fuera, digamos, 8, entoncesa
se cambiaría a 11. Este es un código que en realidad podría tener un propósito, a diferencia de los otros ejemplos.fuente
Declara una función llamada foo que devuelve una referencia a un
int
. Lo que esos ejemplos no consiguen es darte una definición de esa función que podrías compilar. Si usamosAhora tenemos una función que devuelve una referencia a
bar
. dado que bar esstatic
, seguirá vivo después de la llamada a la función, por lo que devolver una referencia a ella es seguro. Ahora si lo hacemosLo que sucede es que asignamos 42 a
bar
ya que asignamos a la referencia y la referencia es solo un alias parabar
. Si volvemos a llamar a la función comoImprimiría 42 ya que lo establecimos
bar
arriba.fuente
int &foo();
declara una función llamadafoo()
con tipo de retornoint&
. Si llama a esta función sin proporcionar un cuerpo, es probable que obtenga un error de referencia indefinido.En su segundo intento proporcionó una función
int foo()
. Tiene un tipo de retorno diferente al de la función declarada porint& foo();
. Por lo tanto, tiene dos declaraciones de la mismafoo
que no coinciden, lo que viola la regla de una definición y causa un comportamiento indefinido (no se requiere diagnóstico).Para algo que funcione, saque la declaración de función local. Pueden conducir a un comportamiento silencioso indefinido como ha visto. En su lugar, solo use declaraciones de función fuera de cualquier función. Su programa podría verse así:
fuente
int& foo();
es una función que devuelve una referencia aint
. Su función proporcionada regresaint
sin referencia.Puedes hacer
fuente
int & foo();
significa quefoo()
devuelve una referencia a una variable.Considere este código:
Este código imprime:
$ ./a.out k = 5
Porque
foo()
devuelve una referencia a la variable globalk
.En su código revisado, está enviando el valor devuelto a una referencia, que luego no es válida.
fuente
En ese contexto, & significa una referencia, por lo que foo devuelve una referencia a un int, en lugar de un int.
No estoy seguro de si hubiera trabajado con punteros todavía, pero es una idea similar, en realidad no está devolviendo el valor de la función, sino que está pasando la información necesaria para encontrar la ubicación en la memoria donde eso int es.
Entonces, para resumir, no está asignando un valor a una llamada de función; está usando una función para obtener una referencia y luego asigna el valor al que se hace referencia a un nuevo valor. Es fácil pensar que todo sucede a la vez, pero en realidad la computadora hace todo en un orden preciso.
Si se está preguntando, la razón por la que está obteniendo un error de segmento es porque está devolviendo un literal numérico '2', por lo que es el error exacto que obtendría si definiera un int const y luego intentara modificar su valor.
Si aún no ha aprendido acerca de los punteros y la memoria dinámica, le recomendaría eso primero, ya que hay algunos conceptos que creo que son difíciles de entender a menos que los esté aprendiendo todos a la vez.
fuente
El código de ejemplo en la página vinculada es solo una declaración de función ficticia. No se compila, pero si tuviera alguna función definida, funcionaría en general. El ejemplo significaba "Si tuvieras una función con esta firma, podrías usarla así".
En su ejemplo,
foo
claramente devuelve un lvalue basado en la firma, pero devuelve un rvalue que se convierte en un lvalue. Esto claramente está decidido a fallar. Podrías hacerlo:y tendría éxito cambiando el valor de x, al decir:
fuente
La función que tiene, foo (), es una función que devuelve una referencia a un número entero.
Entonces, digamos que originalmente foo devolvió 5, y más adelante, en su función principal, dice
foo() = 10;
, luego imprime foo, imprimirá 10 en lugar de 5.Espero que tenga sentido :)
También soy nuevo en la programación. ¡Es interesante ver preguntas como esta que te hacen pensar! :)
fuente