ejemplos descargar definicion compiler caracteristicas c++

c++ - descargar - Pasando como const y por referencia-¿Vale la pena?



c++ manual (6)

¿Quieres copiar los objetos pasados ​​a la función? Si pasa los objetos "Vector a" y "Vector b" por valor, tiene que lidiar con la sobrecarga de copiarlos. Para estructuras pequeñas la sobrecarga es despreciable.

Si pasa los objetos por referencia o por puntero, no tiene esta sobrecarga. Sin embargo, pasar por el puntero o la referencia permite potencialmente la modificación del objeto:

La palabra clave const delante del nombre del objeto se utiliza para garantizar que su función no modifique los objetos que se pasan a la función por referencia o puntero. Esto no solo le dirá a otros programadores que su función es segura de usar, sino que también es aplicada estrictamente por el compilador. La palabra clave const no tiene un impacto en el rendimiento cuando se usa para este propósito.

Si tiene objetos grandes, const reference por const reference const pointer o const pointer . Si desea modificar el objeto que se pasa a la función, utilice una referencia o un puntero. Si su objeto es una estructura pequeña, puede pasarlo por valor.

Posible duplicado:
¿Cómo pasar objetos a funciones en C ++?

En mi juego hago un uso excesivo de vectores matemáticos y la sobrecarga de los operadores.

class Vector { float x, y; };

Eso es básicamente todo acerca de mi clase Vector (métodos excluidos).

No soy un experto en C ++ y he visto y leído acerca de pasar como const y pasar por referencia.

Entonces, ¿dónde están las diferencias de rendimiento en el siguiente ejemplo de código?

Float RandomCalculation( Vector a, Vector b ) { return a.x * b.x / b.x - a.x * RANDOM_CONSTANT; } // versus.. Float RandomCalculation( Vector& a, Vector& b ) { return a.x * b.x / b.x - a.x * RANDOM_CONSTANT; } // versus.. Float RandomCalculation( const Vector& a, const Vector& b ) { return a.x * b.x / b.x - a.x * RANDOM_CONSTANT; }

  • ¿Cuál de los tres debo usar y por qué?
  • ¿Qué ventajas tiene para el proceso de optimización del compilador cada una de las opciones?

  • ¿Cuándo y dónde tengo que ser especialmente cuidadoso?


La respuesta corta es que habrá poca diferencia en la práctica.

Ahora para la respuesta larga:

Habrá una diferencia de rendimiento entre la primera y la segunda versión, y puede haber una diferencia entre la segunda y la tercera.

Cuando llame a la primera versión ( Vector a, Vector b ), se hará una copia de cada uno de los argumentos en la pila. Esto implica asignar memoria de pila y copiar los campos miembros de la clase Vector.

La segunda versión no copiará los objetos vectoriales. En su lugar, la memoria se asignará a las dos referencias (probablemente de 4 u 8 bytes cada una dependiendo de su máquina) y se llenará con la dirección de los objetos vectoriales de la persona que llama. Esto es un poco menos asignación de memoria y un par menos de escrituras.

La tercera versión probablemente no tendrá más rendimiento. La palabra clave const es útil para garantizar que su código se ejecute sin efectos secundarios inesperados, por lo que probablemente sea una buena práctica usarlo, pero es poco probable que resulte en un código más rápido. El compilador puede usar const como una sugerencia que permita algunas optimizaciones, pero podría realizar esas optimizaciones de todos modos.

En su caso, la clase Vector es tan pequeña que es poco probable que exista alguna diferencia práctica a menos que esté haciendo una gran cantidad de llamadas. Es mucho más importante comprender las diferentes semánticas entre la primera y la segunda versión. En la primera versión, los cambios en a y b no afectan la vista de la persona que llama de esos objetos. En la segunda versión (con referencias) los cambios en b afectan la vista de la persona que llama.

Larga historia corta: primero entienda bien la semántica, luego preocupe por la optimización. Tenga cuidado con la optimización prematura. Si realmente desea optimizar este tipo de cosas, obtenga un buen libro sobre los aspectos internos de C ++ y obtenga una comprensión profunda de lo que hace el compilador cuando encuentra funciones de paso por valor y de paso por referencia.

En su caso, sugeriría usar la versión 3 porque el ''const'' muestra su intención y el paso por referencia elimina una copia innecesaria.

EDIT: templatetypedef lo dijo mejor.


Obtendrá muchas respuestas a esta pregunta que afirman una cosa u otra. La verdad del asunto es que necesitas probarlo. Su objeto es bastante pequeño, por lo que pasar por valor puede ser tan rápido o más rápido que pasar por referencia. Sólo al perfilar su código podrá saber.


Pasar por referencia const es la forma preferida de pasar objetos como una alternativa inteligente al paso por valor. Cuando pasa por referencia const , toma el argumento por referencia (evitando hacer copias de él), pero no puede hacer ningún cambio en el objeto original (como sucedería cuando tomaría los parámetros por valor).

Si consideras estas tres funciones:

void VersionOne(Vector v); void VersionTwo(Vector& v); void VersionThree(const Vector& v);

Hay distinciones sutiles entre todos ellos. La primera función, por ejemplo, invocará al constructor de copias cuando pase un Vector para que tenga su propia copia local del Vector . Si su constructor de copias tarda un tiempo en ejecutarse o realiza una gran cantidad de asignación de recursos y desasignación, esto puede ser lento, pero puede realizar los cambios que desee en el parámetro sin correr el riesgo de que los cambios se propaguen al llamante. También habrá una llamada de destructor al final de la función a medida que se limpie el argumento, y si es un costo demasiado alto, puede ser recomendable evitar esta configuración. Dicho esto, para objetos pequeños puede ser perfectamente aceptable.

La segunda versión de esta función incluye un Vector por referencia, lo que significa que la función puede realizar los cambios que desee en el Vector y los cambios se propagarán de nuevo a la persona que llama. Cada vez que vea una función que toma un argumento por referencia no const , como esta función VersionTwo , debe asumir que modificará el argumento, ya que si no hiciera ninguna modificación, se tomaría por referencia const . Lo más probable es que tome el valor por referencia si necesita realizar cambios en el Vector ; por ejemplo, girándolo, escalando, etc. Una de las compensaciones involucradas aquí es que el Vector no se copiará cuando se pase a esta función, por lo que evitará una llamada al constructor y destructor de la copia. Esto puede tener implicaciones de rendimiento para su programa, aunque si ese es su razonamiento, probablemente debería ir con referencia paso a paso. Una cosa a tener en cuenta es que seguir una referencia es muy similar a seguir a un puntero (de hecho, la mayoría de las implementaciones de referencias solo las tratan como si fueran punteros sin referencia automática), por lo que puede haber un pequeño impacto en el rendimiento cada vez que acceda al Datos a través de la referencia. Sin embargo, solo el perfil puede decirle si esto es o no un problema importante, y no me preocuparía si no tuviera una razón específica para pensar que fue culpa suya.

La versión final de esta función incluye una referencia de Vector por const , que, como pasar por referencia regular, evita cualquier copia. Sin embargo, al tomar la referencia Vector by const , tiene prohibido realizar cambios en el Vector dentro de la función, por lo que los clientes pueden asumir que el Vector no se modificará. (Sí, técnicamente podría modificarse si está mal escrito o tiene miembros de datos mutable , pero lo ignoraremos por ahora. Es la idea de alto nivel que es importante aquí). Esta opción sería buena si quisiera poder inspeccionar el valor en la función sin copiarlo y sin mutarlo.

Hay una diferencia más entre el paso por referencia y el paso por referencia, y ese es el comportamiento de la función en rvalues. Si tiene un objeto Vector temporal (ya sea que lo haya creado explícitamente al escribir Vector() o al realizar una operación matemática en él, como escribir v1 + v2 ), no puede pasar ese Vector temporal a una función que toma su parámetro por referencia porque las referencias Solo se puede enlazar a lvalues. La idea es que si tienes una función como esta:

void DoSomething(Vector& v) { v.x = 0.0f; }

Entonces no tiene sentido escribir

DoSomething(v1 + v2);

Dado que esto sería cambiar el campo x de una expresión temporal. Para evitar esto, el compilador se negará a compilar este código.

Sin embargo, C ++ hace una excepción y le permite pasar valores a funciones que toman su argumento por referencia const , ya que, intuitivamente, no debería poder modificar un objeto a través de una referencia const . Por lo tanto este código es perfectamente legal:

void DoSomething(const Vector& v) { cout << v.x << endl; } DoSomething(v1 + v2);

Entonces, para resumir-

  1. El paso por valor y el paso por const referencia implican cosas similares: desea poder mirar el valor sin poder modificarlo.
  2. En cualquier momento que pueda usar el paso por valor, puede usar el paso por la referencia const sin afectar la corrección del programa. Sin embargo, hay compensaciones de rendimiento entre la indirección de la referencia y el costo de copiar y destruir el parámetro.
  3. La referencia paso a paso no se debe usar para indicar "Quiero modificar el argumento".
  4. No puede pasar valores en funciones que toman sus argumentos por referencia no const .

¡Espero que esto ayude!


Puede ser que ahora las cosas cambien, pero hice algunas pruebas hace muchos años con varios compiladores de C ++ y diferentes variaciones (por ejemplo, operator+ miembros o no miembros, operator+ definido en términos de operator+= o no, pase por valor o por ref y similar) .

Revisé ambos tiempos y el código del ensamblador generado. Los resultados fueron altamente dependientes de qué compilador se utilizó ... lo mejor para uno no fue lo mejor para otro.

Además, lamentablemente, en ese momento nunca pude obtener el mismo rendimiento del código C que se desenrolla manualmente y realiza los mismos cálculos. Cierra sí ... pero C todavía era algo más rápido.


Solo pasa por referencia a no constantes si desea cambiar los argumentos y que el cliente observe esos cambios.

Si no desea cambiar los argumentos, pase por referencia a const o por valor.

Si desea cambiar los argumentos pero no tiene ningún efecto en el cliente, pase por valor.