valores valor significa retornan referencia qué que por paso parámetros parametros funciones datos con c++ performance function return-value pass-by-reference

c++ - significa - ¿Qué es más eficiente: devolver un valor vs. Pasar por referencia?



paso de datos por referencia en c (7)

Algunas de las respuestas han tocado esto, pero me gustaría enfatizar a la luz de la edición

Para el contexto, esta pregunta se limita a las diferencias independientes de la plataforma de hardware, y en su mayor parte también al software. ¿Hay alguna diferencia de rendimiento independiente de la máquina?

Si este es el límite de la pregunta, la respuesta es que no hay respuesta. La especificación de c ++ no estipula cómo se implementa el rendimiento de un objeto o un paso por referencia en cuanto al rendimiento, solo la semántica de lo que ambos hacen en términos de código.

Por lo tanto, un compilador es libre de optimizar uno a un código idéntico al otro, suponiendo que esto no cree una diferencia perceptible para el programador.

A la luz de esto, creo que es mejor usar el que sea más intuitivo para la situación. Si la función realmente "devuelve" un objeto como resultado de alguna tarea o consulta, devuélvala, mientras que si la función está realizando una operación en algún objeto propiedad del código externo, pase por referencia.

No se puede generalizar el rendimiento en esto. Para empezar, haga lo que sea intuitivo y vea qué tan bien lo optimiza su sistema y compilador de destino. Si después de crear un perfil descubrirá un problema, cámbielo si es necesario.

Actualmente estoy estudiando cómo escribir un código C ++ eficiente, y sobre el tema de las llamadas a funciones, me viene a la mente una pregunta. Comparando esta función de pseudocódigo:

not-void function-name () { do-something return value; } int main () { ... arg = function-name(); ... }

con esta función de pseudocódigo idéntica:

void function-name (not-void& arg) { do-something arg = value; } int main () { ... function-name(arg); ... }

¿Qué versión es más eficiente y en qué aspecto (tiempo, memoria, etc.)? Si depende, ¿cuándo sería el primero más eficiente y cuándo el más eficiente sería el segundo?

Editar : por contexto, esta pregunta se limita a las diferencias independientes de la plataforma de hardware y, en su mayor parte, también al software. ¿Hay alguna diferencia de rendimiento independiente de la máquina?

Editar : no veo cómo esto es un duplicado. La otra pregunta es comparar pasar por referencia (código anterior) con pasar por valor (a continuación):

not-void function-name (not-void arg)

Lo cual no es lo mismo que mi pregunta. Mi enfoque no está en cuál es la mejor manera de pasar un argumento a una función. Mi enfoque está en cuál es la mejor manera de pasar un resultado a una variable desde el alcance externo.


Bueno, uno debe entender que la compilación no es un negocio fácil. Hay muchas consideraciones tomadas cuando el compilador compila su código.

Uno no puede simplemente responder esta pregunta porque el estándar C ++ no proporciona el estándar ABI (interfaz binaria abstracta), por lo que cada compilador puede compilar el código lo que quiera y puede obtener diferentes resultados en cada compilación.

Por ejemplo, en algunos proyectos, C ++ se compila en una extensión administrada de Microsoft CLR (C ++ / CX). Como todo lo que ya existe es una referencia a un objeto en el montón, supongo que no hay diferencia.

La respuesta no es más simple para las compilaciones no administradas. cuando pienso en "¿XXX funcionará más rápido que YYY?", por ejemplo:

  • ¿Eres objeto sordo-constructible?
  • ¿Su compilador admite la optimización del valor de retorno?
  • ¿Su objeto admite semántica de solo copia o tanto copiar como mover?
  • ¿El objeto está empaquetado de manera contigua (por ejemplo, std::array ) o tiene un puntero a algo en el montón? (por ejemplo, std::vector )?

Si doy un ejemplo concreto, supongo que en MSVC ++ y GCC, devolver std::vector por valor será como pasarlo por referencia, debido a la optimización del valor r, y será un poco (por unos pocos nanosegundos) más rápido luego devolviendo el vector por movimiento. Esto puede ser completamente diferente en Clang, por ejemplo.

eventualmente, la elaboración de perfiles es la única respuesta verdadera aquí.


En cuanto al rendimiento, las copias son generalmente más caras, aunque la diferencia puede ser insignificante para los objetos pequeños. Además, su compilador podría optimizar una copia de retorno en un movimiento, haciendo equivalente a pasar una referencia.

Recomiendo no pasar referencias no const menos que tenga una buena razón para hacerlo. Utilice el valor de retorno (por ejemplo, funciones del tipo tryGet() ).

Si lo desea, puede medirse la diferencia, como ya lo han dicho otros. Ejecute el código de prueba unos millones de veces para ambas versiones y vea la diferencia.


En primer lugar, tenga en cuenta que devolver un objeto siempre será más legible (y muy similar en rendimiento) que pasarlo por referencia, por lo que podría ser más interesante para su proyecto devolver el objeto y aumentar la legibilidad sin tener diferencias de rendimiento importantes . Si desea saber cómo tener el costo más bajo, lo que necesita es devolver:

  1. Si necesita devolver un objeto simple o básico, el rendimiento sería similar en ambos casos.

  2. Si el objeto es tan grande y complejo, devolverlo necesitaría una copia, y podría ser más lento que tenerlo como parámetro referenciado, pero creo que gastaría menos memoria.

De todos modos, debe pensar que los compiladores realizan muchas optimizaciones que hacen que ambas actuaciones sean muy similares. Ver Copia Elision .


Esta función de pseudocódigo:

not-void function-name () { do-something return value; }

se utilizaría mejor cuando el valor devuelto no requiera más modificaciones. El parámetro pasado solo se modifica en el function-name la function-name . No se requieren más referencias para ello.

función de pseudocódigo de otra manera idéntica:

void function-name (not-void& arg) { do-something arg = value; }

sería útil si tenemos otro método para moderar el valor de la misma variable y necesitamos mantener los cambios realizados en la variable por cualquiera de las llamadas.

void another-function-name (not-void& arg) { do-something arg = value; }


La devolución del objeto debe usarse en la mayoría de los casos debido a una optimización llamada copia de elisión .

Sin embargo, dependiendo de cómo se vaya a utilizar su función, puede ser mejor pasar el objeto por referencia.

Mire std::getline por ejemplo, que toma una std::string por referencia. Esta función está diseñada para usarse como una condición de bucle y sigue llenando un std::string hasta que se alcanza EOF. El uso del mismo std::string permite que el espacio de almacenamiento del std::string se reutilice en cada iteración del bucle, reduciendo drásticamente el número de asignaciones de memoria que deben realizarse.


No podemos ser 100% generales porque las diferentes plataformas tienen diferentes ABI, pero creo que podemos hacer algunas declaraciones bastante generales que se aplicarán en la mayoría de las implementaciones con la advertencia de que estas cosas se aplican principalmente a funciones que no están en línea.

En primer lugar, consideremos los tipos primitivos. En un nivel bajo, un paso de parámetro por referencia se implementa utilizando un puntero, mientras que los valores de retorno primitivos generalmente se pasan literalmente en registros. Por lo tanto, es probable que los valores de retorno funcionen mejor. En algunas arquitecturas, lo mismo se aplica a las estructuras pequeñas. Copiar un valor lo suficientemente pequeño como para caber en uno o dos registros es muy barato.

Ahora consideremos valores de retorno más grandes pero aún simples (sin constructores predeterminados, constructores de copia, etc.). Por lo general, los valores de retorno más grandes se manejan pasando la función de un puntero a la ubicación donde se debe colocar el valor de retorno. Copiar elisión permite que la variable devuelta por la función, la temporal utilizada para el retorno y la variable en la persona que llama en la que se coloca el resultado se fusionen en una sola. Por lo tanto, los conceptos básicos de pasar serían muy similares para pasar por referencia y valor de retorno.

En general, para los tipos primitivos, esperaría que los valores de retorno fueran marginalmente mejores y para los tipos más grandes pero aún simples, esperaría que fueran iguales o mejores a menos que su compilador sea muy malo en la copia de elisión.

Para los tipos que usan constructores predeterminados, constructores de copia, etc., las cosas se vuelven más complejas. Si la función se llama varias veces, los valores de retorno obligarán a que el objeto se reconstruya cada vez que los parámetros de referencia pueden permitir que la estructura de datos se reutilice sin ser reconstruida. Por otro lado, los parámetros de referencia forzarán una construcción (posiblemente innecesaria) antes de que se llame a la función.