c++ rvalue temporaries

¿Todos los valores temporales son en C++?



rvalue temporaries (7)

Si no, ¿alguien puede darme un ejemplo donde el código temporal producido en el código es un valor l?

El siguiente código vincula una referencia constante a un objeto temporal de tipo const float creado por el compilador:

int i; const float &cfr = i;

El comportamiento es " como si ":

int i; const float __tmp_cfr = i; // introduced by the compiler const float &cfr = __tmp_cfr;

He estado codificando en C ++ durante los últimos años. Pero hay una pregunta que no he podido descifrar. Quiero preguntar, ¿todos son temporales en C ++, valores?

Si no, ¿alguien puede darme un ejemplo donde el código temporal producido en el código es un valor l ?


Depende de lo que consideres que es una variable temporal. Puedes escribir algo como

#include <stdio.h> int main() { char carray[10]; char *c=carray+1; *(c+2+4) = 9; printf("%d/n",carray[7]); return 0; }

Esto se ejecuta en VisualStudios y GCC. Puede ejecutar el código en el codepad

Considero (c + 2 + 4) un valor agregado aunque quiero asignarlo. Cuando lo desreferencia, se convertiría en un lvalue. Entonces, sí, todos los temporales son valores. Pero puede hacer rvalues ​​(por lo tanto, un temporal) en un lvalue desreferenciando


No.

La especificación del lenguaje C ++ nunca hace una afirmación tan directa como la que está preguntando. No dice en ningún lugar en el estándar de lenguaje que "todos los objetos temporales son valores r". Además, la pregunta en sí misma es un poco incorrecta, ya que la propiedad de ser un valor r en el lenguaje C ++ no es una propiedad de un objeto, sino más bien una propiedad de una expresión (es decir, una propiedad de su resultado). Esta es en realidad la forma en que se define en la especificación del lenguaje: para diferentes tipos de expresiones dice cuando el resultado es un valor l y cuando es un valor r. Entre otras cosas, esto en realidad significa que se puede acceder a un objeto temporal como valor r, así como un valor l, dependiendo de la forma específica de expresión que se utiliza para realizar el acceso.

Por ejemplo, el resultado de la expresión literal 2 + 3 es obviamente un valor r, un temporal de tipo int . No podemos aplicar el unario & a él ya que unary & requiere un lvalue como su operando

&(2 + 3); // ERROR, lvalue required

Sin embargo, como todos sabemos, se puede adjuntar una referencia constante a un objeto temporal, como en

const int &ri = 2 + 3;

En este caso, la referencia se adjunta a la temporal, extendiendo la vida útil de esta última. Obviamente, una vez que está hecho, tenemos acceso a ese mismo temporal como un lvalue ri , ya que las referencias son siempre lvalues. Por ejemplo, podemos aplicar fácil y legalmente el unario & a la referencia y obtener un puntero al temporal

const int *pi = &ri;

con ese puntero permaneciendo perfectamente válido mientras persista el temporal.

Otro ejemplo obvio de acceso lvalue a un objeto temporal es cuando accedemos a un objeto temporal de tipo clase a través de this puntero. El resultado de *this es un lvalue (como siempre sucede con el resultado de unario * aplicado a un puntero de datos), pero no cambia el hecho de que el objeto real podría ser fácilmente temporal. Para un tipo de clase dado T , la expresión T() es un valor r, como se establece explícitamente en el estándar de lenguaje, pero el objeto temporal al que se accede mediante la expresión *T().get_this() (con la implementación obvia de T::get_this() ) es un lvalue. A diferencia del ejemplo anterior, este método le permite obtener de inmediato un lvalue no const, que se refiere a un objeto temporal.

Entonces, una vez más, el mismo objeto temporal podría ser fácilmente "visto" como un valor r o como un valor l dependiendo de qué tipo de expresión (qué tipo de ruta de acceso ) use para "mirar" ese objeto.


Prasoon Saurav ya ha vinculado un muy buen hilo de clc ++. Allí, James Kanze explica por qué la pregunta realmente no tiene sentido. Se reduce a:

  • rvalue-ness es una propiedad (booleana) de expresiones: cada expresión es un valor lval o un valor rvalue
  • los temporales no son expresiones

Por esa razón, la pregunta no tiene sentido.

Un buen ejemplo es el siguiente código:

int main() { const int& ri = 4; std::cout << ri << std::endl; }

La int temporal con el valor 4 no es una expresión. La expresión ri que se imprime no es temporal. Es un lvalue, y se refiere a un temporal.


Respuesta corta: sí, pero no voy a citar el estándar, porque probar el punto requeriría abordar todo tipo de temporal que exista. Por definición, un temporal tiene una vida de una declaración, por lo que asignarle cosas a uno sería un estilo pobre en el mejor de los casos.

Respuesta interesante: Copy elision puede hacer (a menudo hace) un objeto temporal idéntico a un objeto lvalue. Por ejemplo,

MyClass blah = MyClass( 3 ); // temporary likely to be optimized out

o

return MyClass( 3 ); // likely to directly initialize object in caller''s frame

Editar: en cuanto a la pregunta de si hay algún objeto temporal en esos casos, §12.8 / 15 menciona

la operación de copia se puede omitir construyendo el objeto temporal directamente en el objetivo de la copia omitida

lo que indicaría que hay un objeto temporal que puede ser idéntico a un lvalor.


Una operación de indexación de matriz es a la vez un valor temporal y un valor l, algo así como un [10] = 1 es un ejemplo de lo que está buscando; el lvalue es un puntero temporal y calculado.


bueno, ese operador de array devuelve una referencia, ¿se puede considerar que cualquier función que devuelve una referencia hace lo mismo? todas las referencias son const, mientras que pueden ser lvalues, modifican lo que hacen referencia, no la referencia en sí misma. lo mismo es cierto para el operador * ,

*(a temp pointer) = val;

Juro que solía usar algún compilador que pasara valores temporales a cualquier función que tomara una referencia,

para que puedas ir:

int Afunc() { return 5; } int anotherFunc(int & b) { b = 34; } anotherFunc(Afunc());

Sin embargo, no puede encontrar uno que le permita hacer eso ahora, la referencia tiene que ser const para permitir el paso de valores temporales.

int anotherFunc(const int & b);

de todos modos, las referencias pueden ser lvalues ​​y temporales, el truco es que la referencia en sí misma no se modifica, solo lo que hace referencia.

si se cuenta el operador -> como operador, los punteros temporales pueden ser lvalues, pero se aplica la misma condición, no es el puntero temporal que se modificará, sino lo que apunta.