diferencia entre un puntero y un parámetro de referencia?

¿Son estos lo mismo?

int foo(bar* p) { return p->someInt(); } 

y

 int foo(bar& r) { return r.someInt(); } 

Ignora el potencial del puntero nulo. ¿Son estas dos funciones funcionalmente idénticas sin importar si someInt() es virtual o si se pasan una bar o una subclase de bar ?

¿Esto corta algo?

 bar& ref = *ptr_to_bar; 

Las referencias de C ++ no se especifican intencionalmente en el estándar que se implementará mediante punteros. Una referencia es más como un “sinónimo” de una variable que un puntero a ella. Esta semántica abre algunas optimizaciones posibles para el comstackdor cuando es posible darse cuenta de que un puntero sería excesivo en algunas situaciones.

Algunas otras diferencias:

  • No puede asignar NULL a una referencia. Esta es una diferencia crucial y la razón principal por la que preferiría una sobre la otra.
  • Cuando toma la dirección de un puntero, obtiene la dirección de la variable del puntero. Cuando toma la dirección de una referencia, obtiene la dirección de la variable a la que se hace referencia.
  • No puedes reasignar una referencia. Una vez que se inicializa apunta al mismo objeto durante toda su vida.

Ignorando todos los azúcares sintácticos y las posibilidades que se pueden hacer con uno y no con el otro y la diferencia entre los indicadores y las referencias explicadas en otras respuestas (a otras preguntas) … ¡Sí, esos dos son funcionalmente exactamente iguales! Ambos llaman a la función y ambos manejan las funciones virtuales igualmente bien.

Y no, tu línea no corta. Solo está vinculando la referencia directamente al objeto apuntado por un puntero.

Algunas preguntas sobre por qué querrías usar una sobre la otra:

  • Diferencia entre puntero y referencia
  • ¿Hay algún beneficio de pasar por el puntero sobre la referencia?
  • Puntero vs. referencia

En lugar de tratar de encontrar las diferencias yo mismo, te deleulo a aquellos en caso de que quieras saber.

La referencia es un puntero constante, es decir, no puede cambiar la referencia para referirse a otro objeto. Si cambia, el valor del objeto de referencia cambia.

Por ejemplo:

  int j = 10; int &i = j; int l = 20; i = l; // Now value of j = 20 int *k = &j; k = &l; // Value of j is still 10 

Sí, son funcionalmente idénticos. Como una referencia requerirá que la configure en un objeto antes de usarla, no tendrá que tratar con punteros nulos o punteros a la memoria no válida.

También es importante ver la diferencia semántica:

  • Use una referencia cuando realmente pase el objeto normal, pero es tan grande que tiene más sentido pasar una referencia al objeto en lugar de hacer una copia (si no está modificando el objeto).
  • Use un puntero cuando quiera tratar con la dirección de la memoria en lugar de con el objeto.

No he usado C ++ en mucho tiempo, así que ni siquiera voy a intentar responder realmente a tu pregunta (lo siento); Sin embargo, Eric Lippert acaba de publicar un excelente artículo sobre punteros / referencias que supuse que te señalaría.

No estoy seguro si alguien contestó tu segunda pregunta escondida en la parte inferior sobre rebanar … no, eso no causará cortes.

El corte es cuando un objeto derivado se asigna (copia) a un objeto de clase base: la especialización de la clase derivada se “corta”. Tenga en cuenta que dije que el objeto está copiado, no estamos hablando de punteros que se copian / asignan, sino de los propios objetos.

En tu ejemplo, eso no está sucediendo. Simplemente está desreferenciando un puntero a un objeto Bar (lo que resulta en un objeto Bar) que se utiliza como el valor r en una inicialización de referencia. No estoy seguro de tener mi terminología correcta …

Como todos los demás han mencionado, en la implementación, las referencias y los indicadores son básicamente los mismos. Hay algunas advertencias menores:

  • No puede asignar NULL a una referencia (shoosh lo menciona): eso es significativo ya que no hay un valor de referencia “no definido” o “no válido”.

  • Puede pasar una variable temporal como referencia constante , pero no es legal pasar un puntero a un temporal.

Por ejemplo, esto está bien:

 class Thingy; // assume a constructor Thingy(int,int) void foo(const Thingy &a) { a.DoSomething(); } void bar( ) { foo( Thingy(1,2) ); } 

pero la mayoría de los comstackdores se quejarán

 void foo2( Thingy * a); void bar2() { foo( &Thingy(1,2) ); } 
  • Tomar la dirección de una variable para obtener un puntero obliga al comstackdor a guardarlo en la memoria. Asignar una referencia a una variable local simplemente crea un sinónimo; en algunos casos, esto puede permitir que el comstackdor conserve los datos en el registro y evite una carga-hit-store . Sin embargo, esto solo se aplica a las variables locales: una vez que se pasa algo como parámetro por referencia, no hay forma de evitar guardarlo en la stack.
 void foo() { int a = 5; // this may be slightly more efficient int &b = a; printf( "%d", ++b ); // than this int *c = &a; printf( "%d", ++(*c) ); } 
  • Del mismo modo, la palabra clave __restrict no se puede aplicar a las referencias, solo a los punteros.

  • No se puede hacer aritmética de puntero con referencias, entonces mientras que si se tiene un puntero en una matriz, entonces el siguiente elemento de la matriz se puede tener a través de p + 1, una referencia solo apunta a una cosa en toda su vida.

Las funciones obviamente no son “lo mismo”, pero con respecto al comportamiento virtual se comportarán de manera similar. En cuanto a la división, esto solo ocurre cuando se trata de valores, no de referencias o punteros.

Intereting Posts