Puntero frente de Referencia


¿Cuál sería la mejor práctica cuando se le da a una función la variable original para trabajar con:

unsigned long x = 4;

void func1(unsigned long& val) {
     val = 5;            
}
func1(x);

O:

void func2(unsigned long* val) {
     *val = 5;
}
func2(&x);

IOW: ¿Hay alguna razón para elegir uno sobre otro?

Author: Robert Harvey, 2008-09-22

12 answers

Mi regla general es:

Utilice punteros si desea hacer aritmética de puntero con ellos (por ejemplo, incrementando la dirección del puntero para pasar a través de un array) o si alguna vez tiene que pasar un puntero NULO.

Utilice referencias de otro modo.

 266
Author: Nils Pipenbrinck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-31 00:11:49

Realmente creo que se beneficiará de establecer las siguientes pautas de codificación de llamadas a funciones:

  1. Como en todos los demás lugares, siempre sea const-correcto.

    • Nota: Esto significa, entre otras cosas, que solo los valores out (ver ítem 3) y los valores pasados por valor (ver ítem 4) pueden carecer del especificador const.
  2. Solo pasa un valor por puntero si el valor 0/NULL es una entrada válida en el contexto actual.

    • Rationale 1: As a caller, ves que cualquier cosa que pases en debe estar en un estado utilizable.

    • Justificación 2: llamado, usted sabe que lo que viene en es en un estado utilizable. Por lo tanto, no se debe realizar ninguna comprobación NULA o manejo de errores para ese valor.

    • Rationale 3: Rations 1 and 2 will be compiler enforced. Siempre captura errores en tiempo de compilación si puedes.

  3. Si un argumento de función es un fuera de valor, luego pásalo por referencia.

    • Razón: No queremos romper el ítem 2...
  4. Elija "pasar por valor" sobre "pasar por referencia const" solo si el valor es un POD ( Una estructura de datos antigua simple) o lo suficientemente pequeño (en memoria) o de otras maneras lo suficientemente barato (en tiempo) para copiar.

    • Justificación: Evitar copias innecesarias.
    • Nota: lo suficientemente pequeño y lo suficientemente barato no son absolutos mensurable.
 69
Author: Johann Gerell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:08

Esto termina siendo subjetivo. La discusión hasta ahora es útil, pero no creo que haya una respuesta correcta o decisiva a esto. Mucho dependerá de las pautas de estilo y sus necesidades en el momento.

Si bien hay algunas capacidades diferentes (si algo puede ser NULO o no) con un puntero, la mayor diferencia práctica para un parámetro de salida es puramente sintaxis. Guía de Estilo C++ de Google ( https://google.github.io/styleguide/cppguide.html#Reference_Arguments ), por ejemplo, ordena solo punteros para los parámetros de salida, y solo permite referencias que son const. El razonamiento es de legibilidad: algo con sintaxis de valor no debe tener significado semántico de puntero. No estoy sugiriendo que esto sea necesariamente correcto o incorrecto, pero creo que el punto aquí es que es una cuestión de estilo, no de corrección.

 24
Author: Aaron N. Tubbs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-18 11:19:55

Debe pasar un puntero si va a modificar el valor de la variable. Aunque técnicamente pasar una referencia o un puntero son lo mismo, pasar un puntero en su caso de uso es más legible ya que "anuncia" el hecho de que el valor será cambiado por la función.

 7
Author: Max Caceres,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-22 15:28:12

Pointers Vs. Refereces

Las referencias son menos potentes que los punteros:

1) Una vez que se crea una referencia, no se puede hacer más tarde para hacer referencia a otro objeto; no se puede volver a crear. Esto a menudo se hace con punteros.

2) Las referencias no pueden ser NULL. Los punteros a menudo se hacen NULOS para indicar que no están apuntando a ninguna cosa válida.

3) Una referencia debe inicializarse cuando se declara. No existe tal restricción con indicadores

Debido a las limitaciones anteriores, las referencias en C++ no se pueden usar para implementar estructuras de datos como la Lista enlazada, Árbol, etc. En Java, las referencias no tienen restricciones anteriores y se pueden usar para implementar todas las estructuras de datos. Las referencias al ser más potentes en Java, es la razón principal por la que Java no necesita punteros.

Las referencias son más seguras y fáciles de usar:

1) Safer: Dado que las referencias deben ser inicializadas, las referencias comodines como es poco probable que existan punteros salvajes. Todavía es posible tener referencias que no se refieran a una ubicación válida

2) Más fácil de usar: Las referencias no necesitan un operador de desreferenciación para acceder al valor. Se pueden utilizar como variables normales. el operador " & " solo se necesita en el momento de la declaración. Además, se puede acceder a los miembros de una referencia de objeto con el operador dot ('.'), a diferencia de los punteros donde se necesita el operador de flecha ( - > ) para acceder a los miembros.

Junto con las razones anteriores, hay pocos lugares como el argumento del constructor de copia donde el puntero no se puede usar. Reference debe ser usado pasar el argumento en copy constructor. Del mismo modo las referencias deben usarse para sobrecargar algunos operadores como ++.

 6
Author: Yogeesh H T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-04 06:02:56

Si tiene un parámetro en el que puede necesitar indicar la ausencia de un valor, es una práctica común hacer que el parámetro sea un valor de puntero y pasar NULL.

Una mejor solución en la mayoría de los casos (desde una perspectiva de seguridad) es usar boost::opcional. Esto le permite pasar valores opcionales por referencia y también como un valor devuelto.

// Sample method using optional as input parameter
void PrintOptional(const boost::optional<std::string>& optional_str)
{
    if (optional_str)
    {
       cout << *optional_str << std::endl;
    }
    else
    {
       cout << "(no string)" << std::endl;
    }
}

// Sample method using optional as return value
boost::optional<int> ReturnOptional(bool return_nothing)
{
    if (return_nothing)
    {
       return boost::optional<int>();
    }

    return boost::optional<int>(42);
}
 5
Author: Kiley Hykawy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-17 21:53:19

Use una referencia cuando pueda, use un puntero cuando tenga que hacerlo. De C++ FAQ: "¿Cuándo debo usar referencias y cuándo debo usar punteros?"

 4
Author: RezaPlusPlus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-23 07:37:01

Una referencia es un puntero implícito. Básicamente, puede cambiar el valor de los puntos de referencia, pero no puede cambiar la referencia para apuntar a otra cosa. Así que mis 2 centavos es que si solo desea cambiar el valor de un parámetro pasarlo como una referencia, pero si necesita cambiar el parámetro para apuntar a un objeto diferente pasarlo usando un puntero.

 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-22 15:23:53

Considere la palabra clave out de C#. El compilador requiere que el autor de la llamada de un método aplique la palabra clave out a cualquier args out, aunque ya sabe si lo son. Con ello se pretende mejorar la legibilidad. Aunque con los IDE modernos me inclino a pensar que este es un trabajo para resaltar la sintaxis (o semántica).

 3
Author: Daniel Earwicker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-25 09:29:45

Punteros

  • Un puntero es una variable que contiene una dirección de memoria.
  • Una declaración de puntero consiste en un tipo base, un * y el nombre de la variable.
  • Un puntero puede apuntar a cualquier número de variables en la vida
  • Un puntero que actualmente no apunta a una ubicación de memoria válida recibe el valor null (Que es cero)

    BaseType* ptrBaseType;
    BaseType objBaseType;
    ptrBaseType = &objBaseType;
    
  • El & es un operador unario que devuelve la dirección de memoria de su operando.

  • El operador de desreferenciación (*) se utiliza para acceder al valor almacenado en la variable a la que apunta el puntero.

       int nVar = 7;
       int* ptrVar = &nVar;
       int nVar2 = *ptrVar;
    

Referencia

  • Una referencia (&) es como un alias a una variable existente.

  • Una referencia (&) es como un puntero constante que se desreferencia automáticamente.

  • Generalmente se usa para listas de argumentos de función y valores de retorno de función.

  • Una referencia debe ser inicializado cuando se crea.

  • Una vez que se inicializa una referencia a un objeto, no se puede cambiar para referirse a otro objeto.

  • No puede tener referencias NULAS.

  • Una referencia const puede referirse a una const int. Se hace con una variable temporal con valor de la const

    int i = 3;    //integer declaration
    int * pi = &i;    //pi points to the integer i
    int& ri = i;    //ri is refers to integer i – creation of reference and initialization
    

introduzca la descripción de la imagen aquí

introduzca la descripción de la imagen aquí

 3
Author: Saurabh Raoot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-13 12:43:18

Pasar por referencia const a menos que haya una razón por la que desee cambiar/mantener el contenido que está pasando.

Este será el método más eficiente en la mayoría de los casos.

Asegúrese de usar const en cada parámetro que no desea cambiar, ya que esto no solo lo protege de hacer algo estúpido en la función, sino que da una buena indicación a otros usuarios de lo que la función hace a los valores pasados. Esto incluye hacer una const puntero cuando solo desea cambiar lo que es apuntado...

 2
Author: NotJarvis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-22 11:43:55

Punteros:

  • Se puede asignar nullptr (o NULL).
  • En el sitio de llamada debe usar & si su tipo no es un puntero en sí, haciendo explicity estás modificando tu objeto.
  • Los punteros pueden ser rebotados.

Referencias:

  • No puede ser nulo.
  • Una vez enlazado, no puede cambiar.
  • Las personas que llaman no necesitan usar explícitamente &. Esto se considera a veces malo porque hay que ir a la implementación de la función para ver si su parámetro se modifica.
 2
Author: Germán Diago,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-29 13:09:06