c++ - pass - pointers perros
C++: diferencia entre ampersand "&" y asterisco "*" en declaración de función/método? (7)
¿Hay algún tipo de diferencia sutil entre ellos?
void a1(float &b) {
b=1;
};
a1(b);
y
void a1(float *b) {
(*b)=1;
};
a1(&b);
?
Ambos hacen lo mismo (o eso parece desde main ()), pero el primero es obviamente más corto, sin embargo, la mayor parte del código que veo utiliza una segunda notación. ¿Hay una diferencia? Tal vez en caso de que sea un objeto en lugar de flotar?
Ambos hacen lo mismo, pero uno usa referencias y uno usa punteros.
Vea mi respuesta aquí para obtener una lista completa de todas las diferencias .
Aparte del azúcar sintáctico, la única diferencia real es la capacidad de un parámetro de función que es un puntero a ser nulo. Entonces, la versión del puntero puede ser más expresiva si maneja el caso nulo correctamente. El caso nulo también puede tener algún significado especial asociado. La versión de referencia solo puede operar en valores del tipo especificado sin una capacidad nula.
En el primer ejemplo con referencias, sabes que b
no puede ser NULL. Con el ejemplo del puntero, b
podría ser el puntero NULL.
Sin embargo, tenga en cuenta que es posible pasar un objeto NULL a través de una referencia, pero es incómodo y el procedimiento llamado puede suponer que es un error haberlo hecho así:
a1(*(float *)NULL);
En el segundo ejemplo, la persona que llama tiene que ponerle un prefijo al nombre de la variable con ''&'' para pasar la dirección de la variable.
Esto puede ser una ventaja: la persona que llama no puede modificar inadvertidamente una variable pasándola como referencia cuando pensaban que estaban pasando por valor.
Funcionalmente en su ejemplo, ambas versiones hacen lo mismo.
El primero tiene la ventaja de que es transparente en el lado de la llamada. Imagina cómo se vería un operador:
cin >> &x;
Y cómo se ve feo para una invocación de intercambio
swap(&a, &b);
Quieres intercambiar a y b. Y se ve mucho mejor que cuando primero tiene que tomar la dirección. Por cierto, bjarne stroustrup escribe que la razón principal de las referencias fue la transparencia que se agregó en el lado de la llamada, especialmente para los operadores. También vea cómo ya no es obvio si el siguiente
&a + 10
Agregaría 10 al contenido de a, llamando al operador + de él, o si agrega 10 a un puntero temporal a a. Agregue eso a la imposibilidad de que no pueda sobrecargar operadores solo para operandos incorporados (como un puntero y un entero). Las referencias lo hacen claro como el cristal.
Los punteros son útiles si quieres poder poner un "nulo":
a1(0);
Luego, en a1 el método puede comparar el puntero con 0 y ver si el puntero apunta a cualquier objeto.
Sí. La notación *
indica que lo que se está pasando en la pila es un puntero, es decir, la dirección de algo. El &
dice que es una referencia. El efecto es similar pero no idéntico:
Tomemos dos casos:
void examP(int* ip);
void examR(int& i);
int i;
Si llamo a examP
, escribo
examP(&i);
que toma la dirección del artículo y lo pasa en la pila. Si llamo a examR
,
examR(i);
No lo necesito; ahora el compilador "de alguna manera" pasa una referencia, lo que prácticamente significa que obtiene y pasa la dirección de i
. En el lado del código, entonces
void examP(int* ip){
*ip += 1;
}
Tengo que asegurarme de eliminar la referencia del puntero. ip += 1
hace algo muy diferente.
void examR(int& i){
i += 1;
}
siempre actualiza el valor de i
.
Para saber más, lea "llamar por referencia" en lugar de "llamar por valor". La &
noción proporciona una llamada C ++ por referencia.
Una gran diferencia que vale la pena notar es lo que sucede afuera, o bien tienes:
a1(something);
o:
a1(&something);
Me gusta pasar argumentos por referencia (siempre uno const :)) cuando no se modifican en la función / método (y luego también puede pasar objetos automáticos / temporales dentro) y pasarlos por un puntero para indicar y alertar al usuario / lector del código que llama al método que el argumento puede y probablemente se modifica intencionalmente dentro.