C++: ¿es el valor devuelto un valor L?


Considere este código:

struct foo
{
  int a;
};

foo q() { foo f; f.a =4; return f;}

int main()
{
  foo i;
  i.a = 5;
  q() = i;
}

Ningún compilador se queja de ello, ni siquiera Clang. ¿Por qué la línea q() = ... es correcta?

Author: Seth Carnegie, 2011-05-24

3 answers

No, el valor devuelto de una función es un valor l si y solo si es una referencia (C++03). (5.2.2 [expr.call] / 10)

Si el tipo devuelto fuera un tipo básico entonces esto sería un error de compilación. (5,17 [expr.ass] / 1)

La razón por la que esto funciona es que se le permite llamar a funciones miembro (incluso a funciones miembro no-const) en valores r de tipo clase y la asignación de foo es una función miembro definida por la implementación: foo& foo::operator=(const foo&). Las restricciones para los operadores en la cláusula 5 solo se aplica a operadores integrados, (5 [expr] / 3), si la resolución de sobrecarga selecciona una llamada de función sobrecargada para un operador, entonces las restricciones para esa llamada de función se aplican en su lugar.

Esta es la razón por la que a veces se recomienda devolver objetos de tipo clase como const objetos (por ejemplo, const foo q();), sin embargo, esto puede tener un impacto negativo en C++0x donde puede inhibir la semántica de movimiento de trabajar como deberían.

 63
Author: CB Bailey,
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-05-24 14:38:16

Porque se pueden asignar estructuras, y su q() devuelve una copia de struct foo por lo que asigna la estructura devuelta al valor proporcionado.

Esto realmente no hace nada en este caso thought porque la estructura cae fuera de alcance después y no guarda una referencia a ella en primer lugar, por lo que no podría hacer nada con ella de todos modos (en este código específico).

Esto tiene más sentido (aunque todavía no es realmente una "mejor práctica")

struct foo
{
  int a;
};

foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }

int main()
{
  foo i;
  i.a = 5;

  //sets the contents of the newly created foo
  //to the contents of your i variable
  (*(q())) = i;
}
 8
Author: Chad,
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-05-24 14:32:10

Una aplicación interesante de esto:

void f(const std::string& x);
std::string g() { return "<tag>"; }

...

f(g() += "</tag>");

Aquí, g() += modifica el temporal, que puede ser más rápido que crear un temporal adicional con + porque el montón asignado para el valor de retorno de g () ya puede tener suficiente capacidad libre para acomodar </tag>.

Verlo correr en ideone.com con GCC / C++11 .

Ahora, que informática novato dijo algo sobre optimizaciones y el mal...? ;-].

 5
Author: Tony Delroy,
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
2014-10-31 16:43:53