valores retornan que paso parametros lenguaje funciones estructuras ejemplos como codigos arreglos c++ c++11 rvalue

c++ - retornan - Parámetros de valor r en una función



funciones que retornan valores en c++ (3)

Me preguntaba sobre un comportamiento de c ++ cuando se pasa un valor r entre las funciones.

Mira este simple código:

#include <string> void foo(std::string&& str) { // Accept a rvalue of str } void bar(std::string&& str) { // foo(str); // Does not compile. Compiler says cannot bind lvalue into rvalue. foo(std::move(str)); // It feels like a re-casting into a r-value? } int main(int argc, char *argv[]) { bar(std::string("c++_rvalue")); return 0; }

Sé que cuando estoy dentro de la función de bar necesito usar la función de move para invocar la función foo . Mi pregunta ahora es ¿por qué?

Cuando estoy dentro de la función de bar , la variable str ya debería ser un valor r , pero el compilador actúa como si fuera un valor l .

¿Alguien puede citar alguna referencia al estándar sobre este comportamiento? ¡Gracias!


Mi pregunta ahora es ¿por qué?

Estoy agregando otra respuesta porque quiero enfatizar una respuesta al "por qué".

A pesar de que las referencias de rvalue nombradas se pueden unir a un rvalue, se tratan como lvalues ​​cuando se usan. Por ejemplo:

struct A {}; void h(const A&); void h(A&&); void g(const A&); void g(A&&); void f(A&& a) { g(a); // calls g(const A&) h(a); // calls h(const A&) }

Aunque un rvalue puede vincularse a a parámetro de f() , una vez enlazado, a ahora se trata como un lvalue. En particular, las llamadas a las funciones sobrecargadas g() y h() resuelven las sobrecargas const A& (lvalue). El tratamiento de a como un valor dentro de f llevaría a un código propenso a error: primero se llamaría la "versión de movimiento" de g() , que probablemente robaría a , y luego el robo de a sería enviado a la sobrecarga de movimientos de h() .

Reference .


El "rvalue" en "rvalue reference" se refiere al tipo de valor al que se puede enlazar la referencia:

  • Las referencias de valores pueden unirse a valores
  • Las referencias de valor pueden vincularse a valores de r
  • (+ un poco más)

Eso es todo lo que hay que hacer. Es importante destacar que no se refiere al valor que se obtiene al utilizar la referencia. Una vez que tenga una variable de referencia (¡cualquier tipo de referencia!), La expresión id que da nombre a esa variable siempre es un valor l. Los valores aparecen en el comodín solo como valores temporales, o como valores de expresiones de llamada de función, o como el valor de una expresión de conversión, o como resultado de la desintegración o de this .

Hay una cierta analogía aquí con la desreferenciación de un puntero: la anulación de la referencia de un puntero es siempre un valor límico, no importa cómo se haya obtenido ese puntero: *p , *(p + 1) , *f() son todos valores l. No importa cómo llegaste por la cosa; Una vez que lo tienes, es un valor.

Retrocediendo un poco, tal vez el aspecto más interesante de todo esto es que las referencias de valores son un mecanismo para convertir un valor en un valor. No existió tal mecanismo antes de C ++ 11 que producía valores mutables. Si bien la conversión de lvalue a rvalue ha sido parte del lenguaje desde sus inicios, tardó mucho más en descubrir la necesidad de la conversión de rvalue a lvalue.


str es una referencia rvalue, es decir , es una referencia solo a rvalues . Pero sigue siendo una referencia, que es un lvalor. Puede usar str como una variable, lo que también implica que es un valor de l, no un valor temporal.

Un lvalor es, de acuerdo con §3.10.1.1:

Un lvalue (llamado así, históricamente, porque los valores pueden aparecer en el lado izquierdo de una expresión de asignación) designa una función o un objeto. [ Ejemplo : Si E es una expresión de tipo puntero, entonces * E es una expresión de valor l que se refiere al objeto o función a la que E apunta . Como otro ejemplo, el resultado de llamar a una función cuyo tipo de retorno es una referencia de valor l es un valor l. - ejemplo final ]

Y un valor es, de acuerdo con §3.10.1.4:

Un rvalue (llamado así, históricamente, porque los rvalues ​​podrían aparecer en el lado derecho de una expresión de asignación) es un xvalue, un objeto temporal (12.2) o un subobjeto del mismo, o un valor que no está asociado con un objeto .

Basado en esto, str no es un objeto temporal, y está asociado con un objeto (con el objeto llamado str ), por lo que no es un valor de r.

El ejemplo para el valor l utiliza un puntero, pero es lo mismo para las referencias y, naturalmente, para las referencias de valor (que son solo un tipo especial de referencias).

Entonces, en su ejemplo, str es un lvalue , así que debe std::move para llamar a foo (que solo acepta rvalues, no lvalues).