lenguaje - Entender la optimización del valor de retorno y los temporales regresados-C++
funciones en lenguaje c (4)
Depende de tu compilador, ¿a qué plataforma te refieres? La mejor manera de averiguarlo es compilar una aplicación de prueba muy pequeña y verificar el ASM que produce tu compilador.
Sí, está bien, aunque nunca mencionas lo que te preocupa; ¿velocidad? ¿estilo? puede hacer una referencia temporal local a una const - la vida útil del temporal se extenderá a la duración de la referencia - ¡pruébelo y compruébelo usted mismo! (Herb Sutter lo explica here ) Ver el final de la publicación, por ejemplo.
IMO casi siempre es mejor confiar en su compilador para optimizar su código para usted. Hay muy pocos casos en los que deba preocuparse por este tipo de cosas (el código de muy bajo nivel es uno de esos ámbitos, donde es interactivo con los registros de hardware).
int foo() { return 42; }
int main(int, char**)
{
const int &iRef = foo();
// iRef is valid at this point too!
}
Por favor considere las tres funciones.
std::string get_a_string()
{
return "hello";
}
std::string get_a_string1()
{
return std::string("hello");
}
std::string get_a_string2()
{
std::string str("hello");
return str;
}
- ¿Se aplicará RVO en los tres casos?
- ¿Está bien devolver un código temporal como en el código anterior? Creo que está bien, ya que lo devuelvo por valor en lugar de devolver cualquier referencia al mismo.
¿Alguna idea?
En dos primeros casos se llevará a cabo la optimización RVO. RVO es una característica antigua y la mayoría de los compiladores lo admiten. El último caso se llama NRVO (RVO con nombre). Esa es una característica relativamente nueva de C ++. El estándar permite, pero no requiere la implementación de NRVO (así como RVO), pero algunos compiladores lo soportan.
Puede leer más acerca de RVO en el Ítem 20 del libro de Scott Meyers Más efectivo en C ++. 35 nuevas formas de mejorar sus programas y diseños .
Here hay un buen artículo sobre NRVO en Visual C ++ 2005.
Primero, está completamente bien devolver un valor temporal por valor, que es lo que haces. Se copia y, aunque el original saldrá del alcance, la copia no lo hará y la persona que llama puede usarlo con seguridad.
En segundo lugar, los tres casos son, de hecho, idénticos (ya que de todos modos no se accede al temporal en el tercer caso) y un compilador incluso podría emitir el mismo código para todos ellos. Por lo tanto, puede usar RVO en los tres casos. Esto es completamente dependiente del compilador.
Todos los casos son correctos. Todos construirán un temporal y aplicarán el constructor de copia del tipo de devolución. Necesariamente, si no hay un constructor de copia, el código fallará.
RVO sucederá en los tres casos bajo la mayoría de los compiladores. La única diferencia es la última donde el estándar no lo fuerza. Esto porque tienes una variable con nombre. Pero la mayoría de los compiladores son lo suficientemente inteligentes como para aplicar RVO a él ... cuanto más tarde se declare la variable nombrada y menos transformaciones se aplique, mejores serán las probabilidades de que se aplique RVO a una variable con nombre.
Por cierto, devolver una referencia es posible, por supuesto, como podría haber visto en otro código. Lo que no debe hacer es devolver un objeto local de referencia ta.
std::string& get_a_string2()
{
std::string str("hello");
return str; //error!
}
Producirá un error de tiempo de compilación, como usted sabe. Sin embargo,
std::string& get_a_string2(std::string& str)
{
// do something to str
return str; //OK
}
Funcionará bien. En este caso, no hay construcción de construcción o copia involucrada. Simplemente la función devuelve una referencia a su argumento.