Sé que las referencias son azúcar sintáctico, para que el código sea más fácil de leer y escribir.
Pero, ¿cuáles son las diferencias?
Resumen de las respuestas y los enlaces que aparecen a continuación:
NULL
), mientras que una referencia siempre se refiere a un objeto.Para aclarar un concepto erróneo:
El estándar C++ es muy cuidadoso para evitar dictar cómo un compilador puede
implementar las referencias, pero todos los compiladores de C++ implementan las referencias como punteros. Es decir, una declaración como:*
int &ri = i;
si no se optimiza por completo, *asigna la misma cantidad de almacenamiento
como un puntero, y coloca la dirección de
i
en ese almacenamiento.*
***Así, tanto un puntero como una referencia utilizan la misma cantidad de memoria.
Como regla general,
Lectura interesante:
Un puntero puede ser reasignado:
int x = 5;
int y = 6;
int *p;
p = &x;
p = &y;
*p = 10;
assert(x == 5);
assert(y == 10);
Una referencia no puede, y debe ser asignada en la inicialización:
int x = 5
int y = 6;
int &r = x;
Un puntero tiene su propia dirección de memoria y tamaño en la pila (4 bytes en x86), mientras que una referencia comparte la misma dirección de memoria (con la variable original) pero también ocupa algo de espacio en la pila. Dado que una referencia tiene la misma dirección que la variable original, es seguro pensar en una referencia como otro nombre para la misma variable. Nota: Lo que apunta un puntero puede estar en la pila o en el montón. Lo mismo ocurre con las referencias. Mi afirmación no es que un puntero deba apuntar a la pila. Un puntero es sólo una variable que contiene una dirección de memoria. Esta variable está en la pila. Ya que una referencia tiene su propio espacio en la pila, y ya que la dirección es la misma que la variable a la que hace referencia. Más información sobre stack vs heap. Esto implica que hay una dirección real de una referencia que el compilador no te dirá.
int x = 0;
int &r = x;
int *p = &x;
int *p2 = &r;
assert(p == p2);
Puedes tener punteros a punteros a punteros ofreciendo niveles extra de indirección. Mientras que las referencias sólo ofrecen un nivel de indirección.
int x = 0;
int y = 0;
int *p = &x;
int *q = &y
int **pp = &p
pp = &q;//*pp = q
**pp = 4;
assert(y == 4);
assert(x == 0);
A los punteros se les puede asignar directamente nullptr
, mientras que a las referencias no. Si te esfuerzas lo suficiente, y sabes cómo, puedes hacer que la dirección de una referencia sea nullptr
. Del mismo modo, si te esfuerzas lo suficiente puedes tener una referencia a un puntero, y entonces esa referencia puede contener nullptr
.
int *p = nullptr;
int &r = nullptr; <--- error de compilación
int &r = *p; <--- probablemente no hay error de compilación, especialmente si el nullptr está escondido detrás de una llamada a una función, y sin embargo se refiere a un int inexistente en la dirección 0
Los punteros pueden iterar sobre un array, puedes usar ++
para ir al siguiente elemento al que apunta un puntero, y + 4
para ir al 5º elemento. Esto es sin importar el tamaño del objeto al que apunta el puntero.
Un puntero necesita ser desreferenciado con *
para acceder a la posición de memoria a la que apunta, mientras que una referencia puede ser utilizada directamente. Un puntero a una clase/estructura utiliza ->
para acceder a sus miembros mientras que una referencia utiliza un .
.
Un puntero es una variable que contiene una dirección de memoria. Independientemente de cómo se implemente una referencia, ésta tiene la misma dirección de memoria que el elemento al que hace referencia.
Las referencias no se pueden meter en un array, mientras que los punteros sí (Mencionado por el usuario @litb)
Las referencias const pueden estar ligadas a temporales. Los punteros no pueden (no sin alguna indirección):
const int &x = int(12); //legal C++
int *y = &int(12); //ilegal hacer referencia a un temporal.
Esto hace que const&
sea más seguro para su uso en listas de argumentos y demás.
Aparte del azúcar sintáctico, una referencia es un puntero const
(no puntero a un const
). Debes establecer a qué se refiere cuando declaras la variable de referencia, y no puedes cambiarlo después.
Actualización: ahora que lo pienso un poco más, hay una diferencia importante.
El objetivo de un puntero const puede ser reemplazado tomando su dirección y usando un const cast.
El objetivo de una referencia no puede ser reemplazado de ninguna manera que no sea UB.
Esto debería permitir al compilador hacer más optimización en una referencia.