La implementación habitual de RVO es que el código de llamada pasa la dirección de un fragmento de memoria donde la función debe construir su objeto de resultado.
Cuando el resultado de la función es directamente una variable automática que no es un argumento formal, esa variable local simplemente puede colocarse en el fragmento de memoria provisto por el llamador, y la declaración de retorno no copia en absoluto.
Para un argumento pasado por valor, el código de máquina que llama tiene que copiar-inicializar su argumento real en la ubicación del argumento formal ’ antes de saltar a la función. Para que la función coloque su resultado allí, primero tendría que destruir el objeto de argumento formal, que tiene algunos casos especiales complicados (por ejemplo, cuando esa construcción se refiere directa o indirectamente al objeto de argumento formal). Por lo tanto, en lugar de identificar la ubicación del resultado con la ubicación del argumento formal, una optimización aquí lógicamente tiene que usar un trozo de memoria proporcionado proporcionado por separado para el resultado de la función.
Sin embargo, un resultado de función que no se pasa en un registro es normalmente proporcionado por la persona que llama. Es decir, de lo que se podría hablar razonablemente como RVO, una especie de RVO disminuido, para el caso de una expresión return
que denota un argumento formal, es lo que sucedería de todos modos. Y no encaja con el texto “ al construir el objeto automático directamente en el valor de retorno de la función ”.
Resumiendo, el flujo de datos que requiere que la persona que llama pase en un valor, significa que es necesariamente la persona que llama la que inicializa el almacenamiento de un argumento formal, y no la función. Por lo tanto, no se puede evitar la copia de un argumento formal en general (ese término comadreja cubre los casos especiales en los que el compilador puede hacer cosas muy especiales, en particular para el código de máquina en línea). Sin embargo, es la función que inicializa cualquier otro objeto automático local ’ s almacenamiento, y luego es ’ s no hay problema para hacer RVO.
En realidad, hay tres objetos que (pueden) obtener copia construida en ese ejemplo (el argumento para 'no_rvo', el valor de retorno de' no_rvo' y 'x_copy'). La construcción de 'x_copy' puede ser eliminada (construyendo el valor de retorno de' no_rvo' directamente en 'x_copy'). – Mankarse
@Mankarse: Creo que eso es exactamente lo que OP está preguntando: ¿por qué no se elimina la construcción de 'x_copy'? – jweyrich
@jweyrich: No, la pregunta es por qué la construcción del valor de retorno no se elimina. Lo que quiero decir es que no es correcto decir que el código _ imprimirá 'X (const X y otro) no_rvo X (const X y otro)', porque el código también podría imprimir 'X (const X y otro) no_rvo X (const X y otros) X (const X y otro) 'si la construcción de' x_copy' no se elimina. – Mankarse