parametros - funciones en c++ ejemplos
Rvalue Reference se trata como un Lvalue? (4)
Publiqué esta respuesta: https://stackoverflow.com/a/28459180/2642059 que contiene el siguiente código:
void foo(string&& bar){
string* temp = &bar;
cout << *temp << " @:" << temp << endl;
}
¿Es
bar
un valor r o un valor l?
Pregunto porque obviamente no puedo tomar la dirección de un valor r, pero sí puedo tomar la dirección de una referencia rvalue como se hace aquí.
Si puede realizar cualquier operación en una referencia de valor que puede hacer en una referencia de valor, ¿cuál es el punto de diferenciar entre los dos con "&&" en lugar de solo "&"?
¿Es
bar
un valor r o un valor l?
La pregunta se responde sola.
Cualquier cosa que tenga un nombre es un lvalue
(1)
.
Entonces la
bar
es un valor.
Su
tipo
es "rvalue reference to
string
", pero es un lvalue de ese tipo.
Si desea tratarlo como un valor r, debe aplicarle
std::move()
.
Si puede realizar cualquier operación en una referencia de valor que puede hacer en una referencia de valor, ¿cuál es el punto de diferenciar entre los dos con "&&" en lugar de solo "&"?
Esto depende de su definición de "realizar una operación".
Una referencia de valor y una referencia de valor (con nombre) son prácticamente idénticas en cómo puede usarlas en expresiones, pero difieren
mucho
en lo que puede vincularlas.
Los valores pueden unirse a las referencias de valor, los valores pueden unirse a las referencias de valor (y cualquier cosa puede unirse a una referencia de valor a
const
).
Es decir, no puede vincular un rvalue a una referencia de lvalue, o viceversa.
Hablemos de un parámetro de función del tipo de referencia rvalue (como su
bar
).
El punto importante no es qué
bar
es, sino qué sabe sobre el valor al que se refiere la
bar
.
Dado que la
bar
es una referencia de valor, usted sabe con certeza que cualquier cosa vinculada a él
era un valor.
Lo que significa que seguramente se destruirá cuando termine la expresión completa, y puede tratarlo de manera segura como un valor (robando sus recursos, etc.).
Si no eres el que hace esto directamente a la
bar
, pero solo quieres pasar la
bar
, tienes dos opciones: o has terminado con la
bar
, y luego debes decirle al siguiente que lo recibe que está vinculado a un rvalue — do
std::move(bar)
.
O tendrá que hacer algunas cosas más con la
bar
, por lo que no querrá que nadie en el medio le robe sus recursos, así que trátelo como una
bar
.
Para resumirlo: la diferencia no está en lo que puede hacer con la referencia una vez que la tenga. La diferencia es lo que puede unirse a la referencia.
(1) Una buena regla general, con excepciones menores: los enumeradores tienen nombres, pero son valores. Las clases, los espacios de nombres y las plantillas de clase tienen nombres, pero no son valores.
¿Es bar un valor r o un valor l ?
Es un lvalue , como lo es cualquier expresión que nombra una variable.
Si puede realizar cualquier operación en una referencia de valor que puede hacer en una referencia de valor, ¿cuál es el punto de diferenciar entre los dos con "&&" en lugar de solo "&"?
Solo puede inicializar una referencia rvalue con una expresión rvalue . Por lo tanto, puede pasar una cadena temporal a su función, pero no puede pasar una variable de cadena sin moverse explícitamente de ella. Esto significa que su función puede asumir que el argumento ya no es deseado y puede moverse de él.
std::string variable;
foo(variable); // ERROR, can''t pass an lvalue
foo(std::move(variable)); // OK, can explicitly move
foo("Hello"); // OK, can move from a temporary
Aquí, en este caso, las referencias denominadas rvalue son valores , mientras que si el tipo de entrada es constante, las referencias rvalue serán rvalue , aquí hay un ejemplo simple:
#include <string>
#include <iostream>
void foo(const std::string&& bar) {
std::string* temp = &bar; // compile error, can''t get address
std::cout << *temp << " @:" << temp << std::endl;
}
int main()
{
foo("test");
return 0;
}
Espero que esto sea útil.
La
bar
expresión es un valor l.
Pero no es una "referencia de valor de cadena".
La
bar
expresión es una referencia de valor.
Puede verificarlo agregando la siguiente línea en foo ():
cout << is_lvalue_reference<decltype((bar))>::value << endl; // prints "1"
Pero estoy de acuerdo con el resto de la explicación de Angew.
Una referencia de valor, después de que se ha vinculado a un valor, es una referencia de valor. En realidad no es solo para parámetros de función:
string&& a = "some string";
string&& b = a; // ERROR: it does not compile because a is not an rvalue
Si puede realizar cualquier operación en una referencia de valor que puede hacer en una referencia de valor, ¿cuál es el punto de diferenciar entre los dos con "&&" en lugar de solo "&"?
Una referencia de rvalue nos permite hacer algunas "operaciones de lvalue" antes de que expire el rvalue.