¿Todos los rvalues temporales están en C++?


He estado codificando en C++ durante los últimos años. Pero hay una pregunta que no he sido capaz de averiguar. Quiero preguntar, son todos temporales en C++, rvalues?

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

Author: Prasoon Saurav, 2010-01-27

7 answers

No.

La especificación del lenguaje C++ nunca hace una afirmación tan directa como la que usted está preguntando. No dice en ninguna parte del estándar de lenguaje que "todos los objetos temporales son rvalues". Además, la pregunta en sí es un poco inapropiada, ya que la propiedad de ser un rvalue 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). Así es como se define en el idioma especificación: para diferentes tipos de expresiones dice cuando el resultado es un lvalue y cuando es un rvalue. Entre otras cosas, esto en realidad significa que se puede acceder a un objeto temporal como rvalue y lvalue, dependiendo de la forma específica de expresión que se use para realizar el acceso.

Por ejemplo, el resultado de la expresión literal 2 + 3 es obviamente un rvalue, un temporal de tipo int. No podemos aplicarle el unario & ya que unario & requiere un lvalue como su operando

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

Sin embargo, como todos sabemos, una referencia constante se puede adjuntar a un objeto temporal, como en{[17]]}

const int &ri = 2 + 3;

En este caso la referencia se adjunta a lo temporal, extendiendo la vida útil de este último. Obviamente, una vez hecho esto, tenemos acceso al mismo temporal que 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 siendo perfectamente válido mientras el temporal persista.

Otro ejemplo obvio de acceso lvalue a un objeto temporal es cuando accedemos a un objeto temporal de tipo clase a través de su puntero this. El resultado de *this es un lvalue (como siempre es el caso con el resultado de unary * aplicado a un puntero de datos), sin embargo, no cambia el hecho de que el objeto real podría ser fácilmente temporal. Para un tipo de clase dado T, expresión T() es un rvalue, como se indica explícitamente en el estándar del lenguaje, sin embargo, el objeto temporal al que se accede a través de 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 inmediatamente un lvalue no calificado por const, que se refiere a un objeto temporal.

Así que, una vez más, el mismo objeto temporal podría ser fácilmente "visto" como un rvalue o como un lvalue dependiendo de qué tipo de expresión (qué tipo de ruta de acceso) se usa para "mirar" ese objeto.

 43
Author: AnT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-27 09:58:59

Prasoon Saurav ya enlazó un hilo clc++ muy bueno. 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 lvalue o un rvalue
  • los temporales son no 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; 
}

El int temporal con 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.

 9
Author: MSalters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-27 08:51:04

Bien, ese operador de matriz devuelve una referencia, ¿cualquier función que devuelve una referencia podría considerarse que hace lo mismo? todas las referencias son constantes, aunque pueden ser lvalues, modifican lo que hacen referencia, no la referencia en sí. lo mismo es cierto para el operador *,

*(a temp pointer) = val;

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

Así que usted podría ir:

int Afunc()
{
   return 5;
}

int anotherFunc(int & b)
{
    b = 34;
}


anotherFunc(Afunc());

No puedo encontrar uno que te permita hacer eso ahora, sin embargo, 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 que es propia no se modifica, solo lo que hace referencia.

Si se cuenta el operador-> como un operador, entonces los punteros temporales pueden ser lvalues, pero se aplica la misma condición, no es el puntero temporal que se cambiaría, sino la cosa a la que apunta.

 1
Author: matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-27 11:48:13

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

 0
Author: Andrew McGregor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-27 07:20:11

Respuesta corta: sí, pero no voy a citar el estándar, porque demostrar el punto requeriría abordar cada tipo de temporal que hay. Por definición, un temporal tiene una vida de una declaración, por lo que asignar cosas a una 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 cuestión de si hay objeto temporal en esos casos, §12.8 / 15 menciona

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

Lo que indicaría que hay un objeto temporal que puede ser idéntico a un lvalue.

 0
Author: Potatoswatter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-27 08:51:23

Depende de lo que consideres 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. Usted puede ejecutar el código en codepad

Considero (c+2+4) un rvalue aunque quiero asignarle. Cuando lo dereference, se convertiría en un lvalue. Así que sí todos los temporales son rvalues. Pero puedes convertir rvalues (por lo tanto un temporal) en un lvalue desreferenciándolo

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-08 09:27:52

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

El siguiente código enlaza 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;
 -3
Author: curiousguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-08 17:01:17