2010-03-24 19 views
12

estoy un poco confundido lo que sucedió en el siguiente código:Modificación de un const través de un puntero no constante


const int e = 2; 

int* w = (int*) &e;   // (1) cast to remove const-ness 
*w = 5;      // (2) 

cout << *w << endl;   // (3) outputs 5 
cout << e << endl;    // (4) outputs 2 

cout << "w = " << w << endl; // (5) w points to the address of e 
cout << "&e = " << &e << endl; 

En (1), w puntos a la dirección de correo. En (2), ese valor se cambió a 5. Sin embargo, cuando se muestran los valores de * w y e, sus valores son diferentes. Pero si imprime el valor de w puntero y & e, tienen el mismo valor/dirección.

¿Cómo es que e aún contenía 2, incluso si se cambió a 5? ¿Se almacenaron en una ubicación separada? O un temporal? Pero ¿cómo es que el valor señalado por w sigue siendo la dirección de e?

+15

Estás en un terreno de comportamiento indefinido: cualquier cosa puede pasar. –

+0

Mi mente está demasiado cansada para ver lo que está sucediendo, pero puede usar const_cast para esto. Si solo pidió comprender lo que está sucediendo, puede ignorar este comentario. – erelender

+3

@erelender: Podría usar 'const_cast' para esto, pero no haría que el comportamiento sea menos indefinido. –

Respuesta

17

Como dije en mi comentario, una vez que modificó el valor de const, está en un comportamiento indefinido, por lo que no tiene mucho sentido hablar de lo que está sucediendo. Pero qué demonios ..

cout << *w << endl;   // (3) outputs 5 
cout << e << endl;    // (4) outputs 2 

En una conjetura, se está evaluando *w en tiempo de ejecución, pero e está siendo tratado como una constante

+0

Tal vez ... otra posibilidad es que el compilador haya notado "* w = 5" justo antes e insertado 5 en la primera línea en lugar de * w – jpalecek

+0

Estoy de acuerdo. Un const int inicializado en el alcance será una constante de tiempo de compilación. –

+0

¿Esto significa que no sirve de nada emitir una variable const a un puntero no const, ya que la modificación a través de ese puntero da como resultado un comportamiento indefinido? – jasonline

8

Sospecho que estás tropezando con el compilador. Que no espera que usted juegue malas pasadas con el correo, así que cuando se ve la línea:

cout << e << endl; 

Simplemente inserta el valor 2 en lugar de buscar el valor real. Puede verificar (o desmentir) esto mirando el desmontaje de su programa.

+0

+1 para spelunking en ensamblaje –

2

Supongo que el compilador usa la constness para optimizar la variable e insertar un valor fijo en el código.

3

Lo único que ocurre es que el compilador tiene algunos cómo optimizar el código de tal manera que cualquier referencia a e se sustituyen por un valor de 2 a pesar de que asigna memoria para el correo

lo que en efecto (afectan?) en la línea de comentario (4) está 'optimizado' para ser

cout << "2" << endln; 
4

supongo que el compilador ha optimizado la salida del valor. Ve que e es const (por lo tanto, no puede cambiar, en teoría) y cambia cout << e << endl; a cout << 2 << endl;. Sin embargo, e todavía tiene que existir porque es utilizado por w, por lo que w correctamente toma su dirección y modifica su valor, pero no lo ve en el cout.

Moraleja de la historia: solo declare las cosas const cuando realmente quiere ser const. Rechazar const ness no es una buena idea.

1

Este tiempo de compilación está cubierta por la sección [dcl.type.cv]/4 de la norma C++ 14 (anterior normas tenían texto similar también):

excepto que cualquier miembro de la clase declaró mutable se puede modificar, cualquier intento de modificar un objeto const durante sus resultados de toda la vida en un comportamiento indefinido.

e es un objeto const, y *w = 5; intentos de modificar ese objeto, por lo tanto el resultado es undefined behavior.

Cuestiones relacionadas