Razones de diseño para el comportamiento de miembros de referencia de clases pasadas por referencia constante

Supongamos que tiene el código

#include <iostream>

struct A{
  int y;
  int& x;
  A():y(0),x(y){}
};



void f(int& x){
  x++;
}

void g(const A& a){
  f(a.x);
  //f(a.y);
}


int main(){
  A a;
  g(a);
  std::cout<<a.y<<std::endl;

}

dentro de g() llamar a f() en y no está permitido porque a se pasa con el modificador const; sin embargo, el valor de y puede modificarse dentro de g() llamando a f en x;

Con punteros, se pueden obtener cosas similares de manera muy similar.

struct B{
  int* x;  
}

y

g(const B&){
   *x++;
}

esta permitido. Esto está perfectamente claro: tenemos un puntero const a int no const. Pero en el ejemplo de referencia anterior, si las referencias SON el objeto, ¿por qué en este caso se comportan como punteros? ¿Cuáles son las políticas de diseño bajo este comportamiento?

preguntado el 31 de julio de 12 a las 13:07

stackoverflow.com/questions/2431596/… es el mismo problema; sin embargo, puede que no vaya lo suficientemente lejos en la motivación. -

@ecatmur: Gracias, es exactamente lo mismo, lo enlazo, pero como dices, la respuesta no va mucho más allá de "porque es como con punteros" -

Referencias no son el objeto, son un referencia a un objeto. -

@ereOn Estoy de acuerdo, pero mira, por ejemplo stackoverflow.com/questions/728233/… -

@FabioDallaLibera: Lo leí. Tenga en cuenta que el "es" en la respuesta aceptada es enfatizado, indicando que se requiere cuidado al interpretar esta oración. A veces es aceptable ver una referencia como el objeto en algunos casos particulares, ya que simplifica la lógica. Sin embargo, es importante recordar que las referencias siguen siendo una bestia diferente. la mayor parte del tiempo. -

3 Respuestas

si las referencias SON el objeto

las referencias son no Sin embargo, los objetos son referencias a objetos.

Tiene razón en que hacer una referencia en sí misma const no es muy útil: dado que no se pueden volver a colocar, no se pueden mutar como punteros en ningún caso.

De hecho, podría ser más útil pensar en una referencia como un puntero constante (¡no un puntero a constante!) con una sintaxis especial.

Tenga en cuenta que si quieres una indirección que propague constancia del árbitro al referente (es decir, para evitar que el f(a.x) llame aquí), puede escribir un estilo de puntero inteligente para hacerlo.


Ejemplo concreto

struct A
{
    int x;
    int *p;
    int &r;

    A() : x(0), p(&x), r(x) {}
};

Ahora en A a:

  • a.x es un int mutable
  • a.p es un puntero mutable (para que podamos volver a colocarlo) a un int mutable (podemos cambiar el valor del entero al que apunta)
  • y a.r es una referencia a un int mutable
    • tenga en cuenta que, dado que no podemos mutar (reubicar) las referencias de todos modos, no significa nada que la referencia en sí sea constante o mutable

... pero en const A b:

  • b.x es un entero constante
  • b.p es un puntero constante (por lo que no podemos volver a colocarlo) a un int mutable
  • b.r es una referencia a un int mutable
    • observe cómo se aplica la constancia al miembro de A (el puntero o la referencia) y no no propagar a través del referente.

Respondido 31 Jul 12, 14:07

Gracias. Me gusta tu respuesta. Ahora un paso más. estructura B{ int* x; } Ahora, una constante B es lo mismo que una B con una constante int*; Sin embargo, con la estructura C{int& x; } x no es una const int&. ¿Cómo lo llamarías? - Fabio Dalla Libera

no, un const B tiene un miembro constante x, es decir int * const B::x. El miembro es un puntero, por lo que el miembro const es un puntero const no es un puntero a const. Por lo tanto, aún puede modificar lo que sea x apunta a, pero no se puede modificar x (volviéndolo a asentar). - Inútil

Gracias. Marqué la respuesta de @ecatmur para informar extractos del estándar, pero también podría marcar su respuesta como respuesta aceptada. Voy a sumar puntos - Fabio Dalla Libera

El idioma real en el estándar es

8.3.2 Referencias [dcl.ref]

1 - [...] [ Nota: Una referencia puede considerarse como el nombre de un objeto. —nota final]

Así que si una referencia es un nombre de un objeto, no un objeto en sí mismo, entonces tiene sentido que hacer que la estructura envolvente sea const hace el nombre const (lo cual no tiene sentido, ya que las referencias no se pueden recuperar), pero no el objeto en sí.

También vemos

6 - Si un typedef, un parámetro de plantilla de tipo o un especificador de tipo decl denota un tipo TR que es una referencia a un tipo T, un intento de crear el tipo "lvalue referencia a cv TR” crea el tipo “lvalue referencia a T” [...]

Dado que el acceso de miembro en un cv objeto crea un cv lvalue, se aplica lo mismo y el cv se extingue la cualificación.

Respondido 31 Jul 12, 13:07

Gracias. Y creo que el comentario de @Useless agrega algo importante aquí: hacer una referencia en sí misma constante no es muy útil: dado que no se pueden volver a colocar, no se pueden mutar como punteros en ningún caso. - Fabio Dalla Libera

¡Gracias! Aquí está el punto 6 en acción: typedef int& C; modelo estructura V{ const X& x; V(X&px):x(px){} }; int principal(){ int x; Cc(x); V v(c); vx=3; } - Fabio Dalla Libera

En C++, las referencias generalmente se implementan mediante punteros. (Yo creo que el sizeof una referencia y un puntero son lo mismo).

De hecho, suelo pensar en las referencias como punteros, pero con una sintaxis diferente.

Respondido 31 Jul 12, 13:07

"Creo que el tamaño de una referencia y el puntero son los mismos" Nop - Saludos y hth. - Alf

Yo también, aunque mucha gente está en contra, ver por ejemplo stackoverflow.com/questions/728233/… - Fabio Dalla Libera

@Cheersandhth.-Alf ¿Estás diciendo que nunca son iguales o solo a veces? - quamrana

@quamrana sizeof(T&) es idénticamente lo mismo que sizeof(T). no tiene relación con el tamaño de un puntero. el tamaño de la memoria utilizada para una referencia puede ser 0 o el mismo que para T*, u otra cosa, a discreción del compilador, y no está disponible a través de sizeof (para comprobarlo puedes poner una referencia en un struct, decir). - Saludos y hth. - Alf

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.