pointer c++ class reference constants

c++ - pointer - El miembro de datos del tipo de referencia proporciona una "laguna" alrededor de la corrección de const



class c++ (3)

Recientemente he tropezado con la siguiente "brecha" en torno a la corrección de const:

struct Inner { int field = 0; void Modify() { field++; } }; struct Outer { Inner inner; }; class MyClass { public: Outer outer; Inner& inner; // refers to outer.inner, for convenience MyClass() : inner(outer.inner) {} void ConstMethod() const { inner.Modify(); // oops; compiles } };

Además, parece que es posible utilizar este vacío para modificar un objeto declarado como const , que creo que es un comportamiento indefinido:

int main() { const MyClass myclass; std::cout << myclass.outer.inner.field << "/n"; // prints 0 myclass.ConstMethod(); std::cout << myclass.outer.inner.field << "/n"; // prints 1 }

Esto me asusta, porque parece que acabo de invocar un comportamiento indefinido relacionado con la corrección de const_cast en un programa que no usa const_cast o const_cast constancia usando un modelo de tipo C.

Entonces, mis preguntas son:

  • ¿Es correcto decir que el programa anterior tiene un comportamiento indefinido?
  • Si es así, ¿es este un error de idioma? ¿Hay una línea en el programa anterior que posiblemente no debería ( no podría razonablemente hacer) compilar?
  • ¿Hay algunas pautas que deben seguirse para evitar esta categoría de comportamiento indefinido en la práctica?

Eso no es un error en el código, recuerde que const se refiere al elemento más interno del declarador. Básicamente, la const en ConstMethod hace la referencia:

Inner& const inner;

Por supuesto, eso no hace ninguna diferencia real porque las referencias no se pueden volver a unir. Piensa en hacer lo mismo con un puntero en su lugar y te darías cuenta de que todavía se podría modificar el interior. Si fuera:

Inner * const inner;

usted podría llamar inner-> Modificar ().


Esto no debería ser un comportamiento indefinido. Sí, myclass.outer se trata como const dentro de MyClass::ConstMethod() const , pero no comenzó su existencia como const y, por lo tanto, debería ser modificable de forma segura a través de referencias no const . Por supuesto, hacerlo puede sorprender a los lectores y / o usuarios de su código, por lo que debe intentar evitar esto.

Esto es análogo a

int x = 5; int * xPtr = &x; const int * constXPtr = &x;

en el que la existencia de constXPtr no (y no debería) evita que uno modifique de x a xPtr .

Vale la pena señalar que tales posibilidades de creación de alias evitan muchas optimizaciones potenciales del compilador.


Cualquier modificación a un objeto const es un comportamiento indefinido, y el fragmento de código sí lo hace.

El programa no está mal formado (lo que luego requeriría un error de compilación), ya que en el punto de inicializar inner , los calificadores de CV aún no han entrado en vigor.

Desde el punto de vista del compilador, emitir una advertencia requeriría analizar todas las rutas de código que conducen a inner.Modify() y probar que inner.Modify() debe referirse a un objeto const , lo cual es imposible en el caso general.

Es probable que la mejor sugerencia no tenga indicadores / referencias internas, que de todos modos son malos.