valores valor tomar referencias referencia qué que punteros puede por paso parámetros parámetro parametros objetos llamadas función funciones elemento ejemplo define código con como clase argumentos c++ pointers parameter-passing pass-by-reference

c++ - referencias - qué elemento define la clase de valores que un parámetro puede tomar



¿Hay beneficios de pasar por puntero sobre pasar por referencia en C++? (6)

Pasando por puntero

  • La persona que llama tiene que tomar la dirección -> no transparente
  • Se puede proporcionar un valor de 0 para nothing significar nothing . Esto se puede utilizar para proporcionar argumentos opcionales.

Pasar por referencia

  • La persona que llama simplemente pasa el objeto -> transparente. Se debe utilizar para la sobrecarga del operador, ya que la sobrecarga para los tipos de punteros no es posible (los punteros son tipos incorporados). Entonces no puedes hacer la string s = &str1 + &str2; utilizando punteros.
  • No hay valores 0 posibles -> La función llamada no tiene que verificarlos
  • La referencia a const también acepta temporales: void f(const T& t); ... f(T(a, b, c)); void f(const T& t); ... f(T(a, b, c)); , los punteros no se pueden usar de esa manera ya que no se puede tomar la dirección de un temporal.
  • Por último, pero no menos importante, las referencias son más fáciles de usar -> menos posibilidades de errores.

¿Cuáles son los beneficios de pasar por puntero sobre pasar por referencia en C ++?

Últimamente, he visto una serie de ejemplos que eligieron pasar argumentos de función por punteros en lugar de pasar por referencia. ¿Hay beneficios para hacer esto?

Ejemplo:

func(SPRITE *x);

con una llamada de

func(&mySprite);

contra

func(SPRITE &x);

con una llamada de

func(mySprite);


Aclaraciones a los posts anteriores:

Las referencias NO son una garantía de obtener un puntero que no sea nulo. (Aunque a menudo los tratamos como tal.)

Mientras que el código es terriblemente malo, como en el caso de sacarte detrás del código malo de la madera, lo siguiente compilará y ejecutará: (Al menos debajo de mi compilador).

bool test( int & a) { return (&a) == (int *) NULL; } int main() { int * i = (int *)NULL; cout << ( test(*i) ) << endl; };

El problema real que tengo con las referencias radica en otros programadores, en adelante denominados IDIOTS , que asignan en el constructor, se desasignan en el destructor y no pueden proporcionar un constructor u operador de copia = ().

De repente, hay un mundo de diferencia entre foo (BAR bar) y foo (BAR & bar) . (Se invoca la operación de copia automática a nivel de bits. La desasignación en el destructor se invoca dos veces).

Afortunadamente los compiladores modernos recogerán esta doble desasignación del mismo puntero. Hace 15 años, no lo hicieron. (Bajo gcc / g ++, use setenv MALLOC_CHECK_ 0 para revisar las formas antiguas). Resultando, bajo DEC UNIX, en la misma memoria asignada a dos objetos diferentes. Un montón de diversión de depuración allí ...

Más prácticamente:

  • Las referencias ocultan que está cambiando los datos almacenados en otro lugar.
  • Es fácil confundir una referencia con un objeto copiado.
  • ¡Los punteros lo hacen obvio!

En "La cuerda suficiente para dispararte en el pie" de Allen Holub se enumeran las siguientes 2 reglas:

120. Reference arguments should always be `const` 121. Never use references as outputs, use pointers

Enumera varias razones por las que se agregaron referencias a C ++:

  • Son necesarios para definir los constructores de copia.
  • Son necesarios para sobrecargas de operador.
  • const referencias const permiten tener una semántica de paso por valor al tiempo que evita una copia

Su punto principal es que las referencias no deben usarse como parámetros de ''salida'' porque en el sitio de la llamada no hay indicación de si el parámetro es una referencia o un parámetro de valor. Así que su regla es usar solo referencias const como argumentos.

Personalmente, creo que esta es una buena regla general, ya que deja más claro cuándo un parámetro es un parámetro de salida o no. Sin embargo, aunque personalmente estoy de acuerdo con esto en general, me permito ser influido por las opiniones de otros en mi equipo si defienden los parámetros de salida como referencias (a algunos desarrolladores les gustan inmensamente).


Me gusta el razonamiento de un artículo de "cplusplus.com:"

  1. Pase por valor cuando la función no quiera modificar el parámetro y el valor sea fácil de copiar (ints, doubles, char, bool, etc ... tipos simples. Std :: string, std :: vector, y todos los demás STL Los contenedores NO son tipos simples.)

  2. Pase por el puntero de const cuando el valor es costoso de copiar Y la función no desea modificar el valor apuntado a Y NULO es un valor válido y esperado que la función maneja.

  3. Pase por el puntero no constante cuando el valor es costoso de copiar Y la función desea modificar el valor apuntado a Y NULO es un valor válido y esperado que la función maneja.

  4. Paso por referencia constante cuando el valor es costoso de copiar Y la función no desea modificar el valor referido Y NULL no sería un valor válido si se usara un puntero en su lugar.

  5. Pase por referencia no cont cuando el valor es caro para copiar Y la función quiere modificar el valor referido Y NULL no sería un valor válido si se usara un puntero en su lugar.

  6. Cuando se escriben funciones de plantilla, no hay una respuesta clara porque hay algunas ventajas que hay que considerar que están más allá del alcance de esta discusión, pero basta con decir que la mayoría de las funciones de la plantilla toman sus parámetros por valor o por (const) referencia Sin embargo, debido a que la sintaxis del iterador es similar a la de los punteros (asterisco a "desreferencia"), cualquier función de la plantilla que espere iteradores como argumentos también aceptará los punteros por defecto (y no verificará NULL ya que el concepto de iterador NULL tiene una sintaxis diferente ).

http://www.cplusplus.com/articles/z6vU7k9E/

Lo que saco de esto es que la principal diferencia entre elegir usar un puntero o un parámetro de referencia es si NULL es un valor aceptable. Eso es.

Si el valor es entrada, salida, modificable, etc. debe estar en la documentación / comentarios sobre la función, después de todo.


Realmente no. Internamente, el paso por referencia se realiza esencialmente pasando la dirección del objeto al que se hace referencia. Por lo tanto, realmente no hay ganancias de eficiencia que se obtengan al pasar un indicador.

Sin embargo, pasar por referencia tiene un beneficio. Se le garantiza tener una instancia de cualquier objeto / tipo que se esté pasando. Si pasa un puntero, corre el riesgo de recibir un puntero NULO. Al usar paso por referencia, usted está presionando un NULL implícito-verifique un nivel a la persona que llama de su función.


Un puntero puede recibir un parámetro NULO, un parámetro de referencia no puede. Si alguna vez existe la posibilidad de que quiera pasar "sin objeto", utilice un puntero en lugar de una referencia.

Además, pasar por el puntero le permite ver explícitamente en el sitio de la llamada si el objeto se pasa por valor o por referencia:

// Is mySprite passed by value or by reference? You can''t tell // without looking at the definition of func() func(mySprite); // func2 passes "by pointer" - no need to look up function definition func2(&mySprite);