Pasar por referencia y valor en C++

Resuelto user36064 asked hace 15 años • 0 respuestas

Me gustaría aclarar las diferencias entre por valor y por referencia.

Hice un dibujo:

Ingrese la descripción de la imagen aquí

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.

user36064 avatar Jan 04 '09 14:01 user36064
Aceptado

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

1se pasa por valor, porque no está vinculado directamente. La implementación puede copiar el temporal y luego vincularlo a la referencia. 2se pasa por valor, porque la implementación inicializa un temporal del literal y luego se vincula a la referencia. 3se pasa por valor, porque el parámetro no tiene tipo de referencia. 4se pasa por valor por la misma razón. 5se 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
Johannes Schaub - litb avatar Jan 04 '2009 11:01 Johannes Schaub - litb

Al pasar por valor:

void func(Object o);

y luego llamando

func(a);

construirá un Objecten la pila y, dentro de su implementación, funcserá referenciado por o. Es posible que aún sea una copia superficial (las partes internas ay opueden apuntar a los mismos datos), por lo que apodría modificarse. Sin embargo, si oes una copia profunda de a, ano 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 oel interior func2hará que esos cambios sean visibles para la persona que llama, que conoce el objeto por el nombre " a".

Flame avatar Jan 04 '2009 07:01 Flame

No estoy seguro de haber entendido correctamente su pregunta. Es un poco confuso. Sin embargo, lo que podría confundirte es lo siguiente:

  1. 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á.

  2. 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.

vboctor avatar Jan 04 '2009 07:01 vboctor

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".

dreeves avatar Jan 04 '2009 07:01 dreeves

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?

jwpfox avatar Jan 04 '2009 09:01 jwpfox