c++ std move
¿Está volviendo sensible con `std:: move` en el caso de declaraciones de devolución múltiples? (1)
Para las variables locales, no hay necesidad de std::move
en la declaración de return
mayor parte del tiempo † , ya que el lenguaje realmente exige que esto suceda automáticamente:
§12.8 [class.copy] p32
Cuando se cumplen o se cumplirían los criterios para elisión de una operación de copia, salvo por el hecho de que el objeto fuente es un parámetro de función, y el objeto que se va a copiar está designado por un lvalue, la resolución de sobrecarga para seleccionar el constructor para la copia es primero se realizó como si el objeto fuera designado por un valor r . Si la resolución de sobrecarga falla, o si el tipo del primer parámetro del constructor seleccionado no es una referencia rvalue al tipo del objeto (posiblemente cv-qualified), la resolución de sobrecarga se realiza nuevamente, considerando el objeto como un valor l. [ Nota: esta resolución de sobrecarga de dos etapas se debe realizar independientemente de si se producirá elisión de copia. Determina el nombre del constructor que se invocará si no se realiza una elisión, y el constructor seleccionado debe estar accesible incluso si se elimina la llamada. -finalizar nota ]
† La elisión de copia está muy restringida en donde se puede aplicar ( §12.8/31
). Una de estas restricciones es que el tipo de objeto fuente debe ser el mismo que el tipo de retorno cv no calificado de la función cuando se trata de una declaración de retorno. Tampoco es aplicable para subobjetos de variables locales que están a punto de quedar fuera del alcance.
Soy consciente de que normalmente no es una buena idea volver con std::move
, es decir
bigObject foo() { bigObject result; /*...*/ return std::move(result); }
en lugar de simplemente
bigObject foo() { bigObject result; /*...*/ return result; }
porque se interpone en el camino de la optimización del valor de retorno. Pero, en el caso de una función con múltiples rendimientos diferentes, particularmente algo así como
class bar {
bigObject fixed_ret;
bool use_fixed_ret;
void prepare_object(bigObject&);
public:
bigObject foo() {
if(use_fixed_ret)
return fixed_ret;
else{
bigObject result;
prepare_object(result);
return result;
}
}
};
Creo que la optimización del valor de retorno normal es imposible en dicha función, por lo que sería una buena idea poner en
return std::move(result);
aquí, o debería hacerlo (IMO más feo, pero eso es discutible)
bigObject foo() {
bigObject result;
if(use_fixed_ret)
result = fixed_ret;
else{
prepare_object(result);
}
return result;
}