1497 votos

¿Cuáles son las diferencias entre una variable de puntero y de referencia de la variable en C++?

Sé referencias azúcar sintáctico, así será más fácil de código para leer y escribir :)

Pero, ¿cuáles son las diferencias?

Resumen de las respuestas y los enlaces a continuación:

  1. Un puntero puede ser re-asignados cualquier número de veces, mientras que una referencia no puede ser re-sentado después de la unión.
  2. Los punteros pueden apuntar a ninguna parte (NULL), mientras que la de referencia se refieren siempre a un objeto.
  3. No se puede tomar la dirección de una referencia de como se puede hacer con los punteros.
  4. No hay ninguna referencia "aritmética" (pero usted puede tomar la dirección de un objeto apuntado por la referencia y hacer aritmética de punteros en él como en &obj + 5).

Para aclarar un malentendido:

El estándar de C++ es muy cuidadoso para evitar el dictado de cómo un compilador debe implementar las referencias, pero cada compilador de C++ implementa referencias como punteros. Es decir, una declaración, tales como:

int &ri = i;

si no está optimizada fuera por completo, asigna la misma cantidad de almacenamiento como un puntero, y coloca la dirección de i, en que el almacenamiento.

Así puntero y de referencia ocupa la misma cantidad de memoria

Como regla general,

  • El uso de referencias en los parámetros de la función y los tipos de devolución para definir útil y de auto-documentación de las interfaces.
  • El uso de punteros para implementar algoritmos y estructuras de datos.

Lectura interesante:

786voto

Brian R. Bondy Puntos 141769
  1. Un puntero puede ser re-asignados:

    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 asignado en la inicialización:

    int x = 5;
    int y = 6;
    int &r = x;
    
  2. Un puntero tiene su propia dirección de memoria y el tamaño de la pila (4 bytes en x86), mientras que una referencia de acciones en la misma dirección de memoria (con la variable original), pero también toma algo de espacio en la pila. Desde una referencia a la misma dirección de la variable original en sí, es seguro pensar en una referencia como otro nombre para la misma variable. Nota: Lo que un puntero apunta a que puede haber en la pila o montón. Ídem de referencia. Mi reclamo en esta declaración no es que un puntero para que apunte a la pila. Un puntero es sólo una variable que contiene una dirección de memoria. Esta variable está en la pila. Desde una referencia tiene su propio espacio en la pila, y dado que la dirección es la misma que la variable que hace referencia. Más sobre la pila vs montón. Esto implica que hay una dirección real de una referencia que el compilador no te digo.

    int x = 0;
    int &r = x;
    int *p = &x;
    int *p2 = &r;
    assert(p == p2);
    
  3. Usted puede tener punteros a punteros a punteros ofrecer nivel 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);
    
  4. Puntero se le puede asignar NULL directamente, mientras que la referencia no puede. Si te esmeras, y saber cómo, puede hacer que la dirección de una referencia NULA. Del mismo modo, si te esmeras usted puede tener una referencia a un puntero y, a continuación, la referencia puede contener NULL.

    int *p = NULL;
    int &r = NULL; <--- compiling error
    
  5. Punteros puede iterar a través de una matriz, puede utilizar ++ para ir al siguiente elemento, que es un puntero que apunta, y + 4 para ir al 5º elemento. Esto es, no importa el tamaño del objeto es la que señala el puntero.

  6. Un puntero tiene que ser eliminan las referencias con * para acceder a la ubicación de la memoria que señala, mientras que una referencia se puede utilizar directamente. Un puntero a una clase o struct usos -> para acceder a sus miembros, mientras que una referencia utiliza un ..

  7. Un puntero es una variable que contiene una dirección de memoria. Independientemente de cómo la referencia se implementa, una referencia a la misma dirección de memoria como el elemento que hace referencia.

  8. Las referencias no puede ser metido dentro de una matriz, mientras que los punteros se puede (Mencionada por el usuario @litb)

  9. Const referencias puede ser obligado a empleos temporales. Punteros no (no sin cierta indirección):

    const int &x = int(12); //legal C++
    int *y = &int(12); //illegal to dereference a temporary.
    

    Esto hace que const& seguro para su uso en las listas de argumentos y así sucesivamente.

160voto

Christoph Puntos 64389

¿Qué es una referencia de C++ (para programadores de C)

Una referencia puede ser pensado como un puntero constante (que no debe confundirse con un puntero a un valor constante!) con detección automática de direccionamiento indirecto, es decir, el compilador se aplicará el * operador para usted.

Todas las referencias deben ser inicializado con un valor no nulo o la compilación fallará. No es ni posible obtener la dirección de una referencia de la dirección del operador devolverá la dirección de la referencia de valor en su lugar - ni es posible hacer aritmética de las referencias.

Los programadores de C podría aversión C++ las referencias ya no será más evidente cuando direccionamiento indirecto sucede o si un argumento se pasa por valor o por el puntero, sin mirar función de firmas.

Los programadores de C++ puede rechazar el uso de punteros, ya que se consideran inseguros - aunque las referencias no son realmente más seguro que la constante de los punteros, excepto en la mayoría de los casos triviales - falta la conveniencia de direccionamiento automático y llevar una diferente connotación semántica.

Considere la siguiente instrucción desde el C++ FAQ Lite:

Aunque la referencia es a menudo implementado utilizando una dirección en la subyacente en lenguaje ensamblador, por favor, qué no pensar en una referencia como un gracioso puntero a un objeto. Una referencia es el objeto. Es no es un puntero al objeto, ni una copia del objeto. Ella esla objeto.

Pero si una referencia realmente fueron objeto, ¿cómo podría haber referencias pendiente? En lenguajes no administrados, es imposible que las referencias a cualquier 'más segura' de punteros - no, en general, no es una forma confiable de alias de valores a través de los límites de ámbito!

¿Por qué considero que C++ las referencias útiles

Viniendo de un C de fondo, C++ las referencias puede parecer un poco tonto concepto, pero por lo que debe utilizar en lugar de punteros, donde sea posible: Automático direccionamiento indirecto es conveniente, y las referencias que se hacen especialmente útil cuando se trata de RAII - pero no porque la percepción de seguridad ventaja, sino más bien porque hace que la escritura idiomática código de menos torpe.

RAII es uno de los conceptos centrales de C++, pero se interactúa no trivial con la copia de la semántica. Pasar objetos por referencia evita estos problemas no copiar está involucrado. Si las referencias no estaban presentes en el lenguaje, usted tendría que usar punteros en su lugar, que son más complicados de usar, violando de esta manera el diseño del lenguaje principio de que la mejor práctica de la solución debe ser más fácil que las alternativas.

95voto

Matt Price Puntos 9674

Si quieres ser realmente pedante, hay una cosa que se puede hacer con una referencia que no se puede hacer con un puntero: extender el tiempo de vida de un objeto temporal. En C++ si se unen una referencia constante a un objeto temporal, el tiempo de vida del objeto se convierte en el curso de la vida de la referencia.

std::string s1 = "123";
std::string s2 = "456";

std::string s3_copy = s1 + s2;
const std::string& s3_reference = s1 + s2;

En este ejemplo s3_copy copias el objeto temporal que es resultado de la concatenación. Mientras que s3_reference, en esencia, se convierte en el objeto temporal. Es realmente una referencia a un objeto temporal que ahora tiene la misma duración que la de referencia.

Si usted intenta esto sin la const se producirá un error de compilación. No se puede enlazar una referencia no const a un objeto temporal, ni se puede tomar su dirección para que la materia.

60voto

Mark Ransom Puntos 132545

Contrariamente a la opinión popular, es posible tener una referencia de que es NULO.

int * p = NULL;
int & r = *p;
r = 1;  // crash! (if you're lucky)

Por supuesto, es mucho más difícil de hacer con una referencia, pero si lo consigues, te voy a arrancar los cabellos tratando de encontrar.

Edit: un par de aclaraciones.

Técnicamente, esta es una referencia no válida, no una referencia nula. C++ no admite referencias nulas como un concepto, como se puede encontrar en otros idiomas. Hay otros tipos de referencias no válidas también.

El error real es la de eliminar el puntero NULL, antes de la asignación a una referencia. Pero yo no soy consciente de que cualquier compiladores que generen errores en esa condición - el error que se propaga en un punto más adelante en el código. Eso es lo que hace que este problema sea tan insidiosa. La mayoría de las veces, si usted desreferenciar un puntero NULO, sufre un accidente justo en ese lugar y que no toma mucho depuración de averiguar.

Mi ejemplo anterior es corto y artificial. Aquí hay más de un ejemplo real.

class MyClass
{
    ...
    virtual void DoSomething(int,int,int,int,int);
};

void Foo(const MyClass & bar)
{
    ...
    bar.DoSomething(a,Long,list,of,parameters);  // crash occurs here - obvious why?
}

MyClass * GetInstance()
{
    if (somecondition)
        return NULL;
    ...
}

MyClass * p = GetInstance();
Foo(*p);

Edit: Algunas reflexiones.

Quiero reiterar que la única manera de obtener una referencia de objeto null es a través de la malformación de código, y una vez que usted está consiguiendo un comportamiento indefinido. Que nunca tiene sentido buscar una referencia nula; por ejemplo, usted puede intentar if(&bar==NULL)... , pero el compilador puede optimizar la declaración de la existencia! Una referencia válida nunca puede ser NULO por lo que desde el compilador de vista de la comparación es siempre falso - esta es la esencia de un comportamiento indefinido.

La forma correcta para mantenerse fuera de problemas es evitar desreferenciar un puntero NULL para crear una referencia. He aquí una forma automatizada para lograr esto.

template<typename T>
T& ref(T* p)
{
    if (p == NULL)
        throw std::invalid_argument(std::string("NULL reference"));
    return *p;
}

MyClass * p = GetInstance();
Foo(ref(p));

53voto

Orion Edwards Puntos 54939

Olvida la parte más importante

miembro-acceso con punteros usa ->
miembro-acceso con referencias usos .

foo.bar es claramente superior al foo->bar de la misma manera que vi es claramente superior a la de emacs :-)

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X