2010-04-06 8 views
29

Por lo que entiendo: cuando pasa por valor, la función hace una copia local del argumento pasado y lo usa; cuando la función finaliza, sale del alcance. Cuando pasa por referencia constante, la función utiliza una referencia al argumento pasado que no se puede modificar. No entiendo, sin embargo, por qué uno elegiría uno sobre el otro, excepto en una situación donde un argumento necesita ser modificado y devuelto. Si tenía una función nula donde no se devuelve nada, ¿por qué elegir una sobre la otra?¿Por qué pasar por referencia const en lugar de por valor?

EDITAR: Así que, básicamente, al pasar por referencia const evita copiar el objeto. Entonces, ¿en qué situaciones está bien copiar el objeto? Quiero decir, ¿por qué no usar referencias continuas todo el tiempo si optimiza el rendimiento todo el tiempo?

+1

posible duplicado de http://stackoverflow.com/questions/1567138/const-t-arg-vs-t-arg –

+0

Los enlaces del artículo gf cubren su segunda pregunta. En resumen: si necesita una copia, pase una. –

+0

@Kirill Ah, eso responde mi pregunta. Busqué "pass by const reference" y no subió nada, así que me perdí esa. – Maulrus

Respuesta

39

Hay dos consideraciones principales. Uno es el costo de copiar el objeto pasado y el segundo son las suposiciones que el compilador puede hacer cuando el objeto es un objeto local.

E.g. En la primera forma, en el cuerpo de f no se puede suponer que a y b no hacen referencia al mismo objeto; por lo que el valor de a debe volver a leerse después de cualquier escritura en b, por si acaso. En la segunda forma, a no se puede cambiar mediante una escritura a b, ya que es local para la función, por lo que estas relecturas son innecesarias.

void f(const Obj& a, Obj& b) 
{ 
    // a and b could reference the same object 
} 

void f(Obj a, Obj& b) 
{ 
    // a is local, b cannot be a reference to a 
} 

E.g.: En el primer ejemplo, el compilador puede suponer que el valor de un objeto local no cambia cuando se realiza una llamada no relacionada. Sin información sobre h, el compilador puede no saber si un objeto al que hace referencia esa función (mediante un parámetro de referencia) no se cambia por h. Por ejemplo, ese objeto puede ser parte de un estado global que se modifica por h.

void g(const Obj& a) 
{ 
    // ... 
    h(); // the value of a might change 
    // ... 
} 

void g(Obj a) 
{ 
    // ... 
    h(); // the value of a is unlikely to change 
    // ... 
} 

Desafortunadamente, este ejemplo no es de hierro fundido. Es posible escribir una clase que, por ejemplo, se agregue un puntero a un objeto de estado global en su constructor, de modo que incluso un objeto local del tipo de clase podría ser alterado por una llamada a función global. A pesar de esto, todavía hay más oportunidades para optimizaciones válidas para objetos locales ya que no pueden ser alias directamente por referencias pasadas u otros objetos preexistentes.

Al pasar un parámetro por const se debe elegir la referencia donde realmente se requiere la semántica de las referencias, o como una mejora del rendimiento solo si el costo del aliasing potencial se compensa por el costo de copiar el parámetro.

+0

En ocasiones, copiar tus parámetros también puede darte beneficios locales. –

+1

¿Qué sentido tiene 'const Obj & a' si los datos a los que se hace referencia pueden cambiar? ¿Por qué incluso tener el 'const' en primer lugar? –

4

Hacer una copia de un objeto podría afectar en gran medida el rendimiento en algunos casos. Considera una función cuyo argumento será std::vector<long> y quieres pasar el vector con 1 millón de elementos. En este caso, querrás usar la referencia constante sobre pasar por valor. En this SO question puede encontrar una regla general simple para su pregunta.

2

A veces, hacer una copia de un objeto puede ser costoso y, por lo tanto, la referencia paso a paso evitará tener que hacer esa copia. De lo contrario, diría que simplemente debe pasar por valor si eso es lo que se requiere semánticamente.

2

Para evite hacer una copia innecesaria, mejorando así el rendimiento.

2

Pasar un argumento por valor tiene la sobrecarga de una copia del objeto que se pasa a la función.

Quizás un objeto no se puede copiar y sus opciones son limitadas.

2

Debido a los beneficios de rendimiento que obtendrá. Digamos que tienes un objeto grande (en términos de tamaño en bytes). Ahora, si pasa este objeto por valor a una función, se necesita crear una copia innecesaria de esto, sin embargo, puede obtener el mismo efecto pasando una referencia constante a ese objeto sin crear una copia. Dado que una referencia se almacena normalmente como un puntero debajo de las capuchas, el costo de pasar una referencia es solo sizeof(pointer).

18

Pasar argumentos por valor y, por lo tanto, copiarlos puede ser costoso: las referencias de referencias evitan ese paso costoso y al mismo tiempo le prometen a la persona que llama que el objeto no se cambiará.

Por lo general, los tipos fundamentales (int, double, ...) se pasan por valor, mientras que los tipos de clase se pasan por referencia de referencia.

Sin embargo, puede haber exceptions donde pasar por valor para los tipos de clase puede ser beneficioso.

2

Una matriz no se puede pasar por valor, por lo que este es un buen momento para usar un puntero const.

Cuestiones relacionadas