Pasar por referencia y valor en C++
Me gustaría aclarar las diferencias entre por valor y por referencia.
Hice un dibujo:
Entonces, para pasar por valor, se crea una copia de un objeto idéntico con una referencia diferente y a la variable local se le asigna la nueva referencia, para apuntar a la nueva copia.
¿Cómo debo entender lo siguiente?
Si la función modifica ese valor, las modificaciones aparecen también dentro del alcance de la función que llama tanto para pasar por valor como por referencia.
Creo que se genera mucha confusión al no comunicar lo que se entiende por pasado por referencia . Cuando algunas personas dicen pasar por referencia, normalmente no se refieren al argumento en sí, sino al objeto al que se hace referencia . Algunos otros dicen que pasar por referencia significa que el objeto no se puede cambiar en el destinatario. Ejemplo:
struct Object {
int i;
};
void sample(Object* o) { // 1
o->i++;
}
void sample(Object const& o) { // 2
// nothing useful here :)
}
void sample(Object & o) { // 3
o.i++;
}
void sample1(Object o) { // 4
o.i++;
}
int main() {
Object obj = { 10 };
Object const obj_c = { 10 };
sample(&obj); // calls 1
sample(obj) // calls 3
sample(obj_c); // calls 2
sample1(obj); // calls 4
}
Algunas personas afirmarían que 1 y 3 se pasan por referencia, mientras que 2 se pasa por valor. Otro grupo de personas dice que todos menos el último se pasan por referencia, porque el objeto en sí no se copia.
Me gustaría dibujar aquí una definición de lo que pretendo pasar por referencia . Puede encontrar una descripción general al respecto aquí: Diferencia entre pasar por referencia y pasar por valor . El primero y el último se pasan por valor y los dos del medio se pasan por referencia:
sample(&obj);
// yields a `Object*`. Passes a *pointer* to the object by value.
// The caller can change the pointer (the parameter), but that
// won't change the temporary pointer created on the call side (the argument).
sample(obj)
// passes the object by *reference*. It denotes the object itself. The callee
// has got a reference parameter.
sample(obj_c);
// also passes *by reference*. the reference parameter references the
// same object like the argument expression.
sample1(obj);
// pass by value. The parameter object denotes a different object than the
// one passed in.
Voto por la siguiente definición:
Un argumento (1.3.1) se pasa por referencia si y sólo si el parámetro correspondiente de la función que se llama tiene un tipo de referencia y el parámetro de referencia se vincula directamente a la expresión del argumento (8.5.3/4). En todos los demás casos, tenemos que hacerlo con pasar por valor.
Eso significa que lo siguiente se pasa por valor:
void f1(Object const& o);
f1(Object()); // 1
void f2(int const& i);
f2(42); // 2
void f3(Object o);
f3(Object()); // 3
Object o1; f3(o1); // 4
void f4(Object *o);
Object o1; f4(&o1); // 5
1
se pasa por valor, porque no está vinculado directamente. La implementación puede copiar el temporal y luego vincularlo a la referencia. 2
se pasa por valor, porque la implementación inicializa un temporal del literal y luego se vincula a la referencia. 3
se pasa por valor, porque el parámetro no tiene tipo de referencia. 4
se pasa por valor por la misma razón. 5
se pasa por valor porque el parámetro no tiene tipo de referencia. Los siguientes casos se pasan por referencia (según las reglas de 8.5.3/4 y otras):
void f1(Object *& op);
Object a; Object *op1 = &a; f1(op1); // 1
void f2(Object const& op);
Object b; f2(b); // 2
struct A { };
struct B { operator A&() { static A a; return a; } };
void f3(A &);
B b; f3(b); // passes the static a by reference
Al pasar por valor:
void func(Object o);
y luego llamando
func(a);
construirá un Object
en la pila y, dentro de su implementación, func
será referenciado por o
. Es posible que aún sea una copia superficial (las partes internas a
y o
pueden apuntar a los mismos datos), por lo que a
podría modificarse. Sin embargo, si o
es una copia profunda de a
, a
no cambiará.
Al pasar por referencia:
void func2(Object& o);
y luego llamando
func2(a);
solo estarás dando una nueva forma de referencia a
. " a
" y " o
" son dos nombres para el mismo objeto. Cambiar o
el interior func2
hará que esos cambios sean visibles para la persona que llama, que conoce el objeto por el nombre " a
".
No estoy seguro de haber entendido correctamente su pregunta. Es un poco confuso. Sin embargo, lo que podría confundirte es lo siguiente:
Al pasar por referencia, se pasa una referencia al mismo objeto a la función que se llama. Cualquier cambio en el objeto se reflejará en el objeto original y, por tanto, la persona que llama lo verá.
Al pasar por valor, se llamará al constructor de copia. El constructor de copia predeterminado solo hará una copia superficial, por lo tanto, si la función llamada modifica un número entero en el objeto, la función que llama no verá esto, pero si la función cambia una estructura de datos apuntada por un puntero dentro del objeto. , la persona que llama verá esto debido a la copia superficial.
Puede que haya entendido mal tu pregunta, pero pensé en intentarlo de todos modos.
Mientras lo analizo, esas palabras están equivocadas. Debería decir "Si la función modifica ese valor, las modificaciones aparecen también dentro del alcance de la función que llama cuando pasa por referencia, pero no cuando pasa por valor".
Mi comprensión de las palabras "Si la función modifica ese valor, las modificaciones aparecen también dentro del alcance de la función que llama tanto para pasar por valor como por referencia" es que son un error .
Las modificaciones realizadas en una función llamada no están dentro del alcance de la función que llama cuando se pasa por valor.
O ha escrito mal las palabras citadas o han sido extraídas de cualquier contexto que hizo que lo que parecía estar mal fuera correcto.
¿Podría asegurarse de haber citado correctamente su fuente y, si no hay errores, proporcionar más texto que rodee esa declaración en el material fuente?