2010-01-05 11 views
13

Estoy tratando de cambiar el valor de una variable que se define como int const como a continuación.cambiando el valor de la variable const en C++

const int w = 10; 
int* wp = const_cast <int*> (&w); 
*wp = 20; 

El valor de w no cambió y era 10 incluso después de la cesión, aunque se muestra como si ambos W y wp están apuntando en la misma ubicación de memoria. Pero yo soy capaz de que el cambio del valor de w, si está definida de la siguiente manera, mientras declarando

int i = 10; 
const int w = i; 

Si cambio de la declaración de i para que sea const como en

const int i = 10; 

El valor de w doesn no cambias

En el primer caso, ¿cómo es que el valor de w no cambió, a pesar de que W y WP apuntan a la misma posición de memoria [que fue mi impresión que tengo al imprimir sus direcciones]

¿Qué diferencia ¿es al compilador que trata ambos casos de manera diferente?

¿Hay alguna forma de asegurarse de que w no pierda la consistencia, independientemente de la forma en que se defina?

+11

Si un objeto se creó inicialmente como 'const', entonces no se puede (no debería)' const_cast' hacerlo a 'no-contr'; ese es un comportamiento indefinido Si un objeto se creó inicialmente como no 'const ', puede' const_cast' adelante y atrás como lo desee. –

+5

En algunas implementaciones, escribir en un objeto 'const' puede bloquear su programa, si el contenido del objeto reside en una sección de solo lectura (por ejemplo,' .rodata' en oposición a '.data', donde los datos no 'const' se sienta). –

+6

Nadie parece haber formulado la pregunta obvia: si desea cambiar el valor, ¿por qué marca la variable como 'const'? –

Respuesta

5

const_cast no quita la const-ness de una variable como se define. Si pasase una variable no const por referencia a un método que tomara una referencia constante como void foo(const int& x), podría usar const_cast para modificar el valor de x dentro de foo, pero solo si la variable que realmente ingresó no estaba const en el primer lugar.

15

Este es uno de los casos en los que un molde constante no está definido, ya que el código probablemente se haya optimizado de forma que w no sea realmente una variable y no exista realmente en el código compilado.

intente lo siguiente:

const volatile int w = 10; 
int &wr = const_cast <int &> (w); 
wr = 20; 
std::cout << w << std::endl; 

De todos modos, yo no aconsejaría a abusar const_cast así.

+3

La diferencia mágica es la palabra clave 'volátil'. Saca eso y w = 10 como en el ejemplo original basado en puntero de Narendra. –

+1

Tiene razón; el calificador volátil se usa para evitar que el compilador optimice. – rmn

+0

He intentado lo mismo en tres compiladores diferentes [Visual C++ Express Edition, g ++ y Sun CC compiler], en los tres compiladores el resultado fue el mismo. Hubo coherencia en los resultados con todos los compiladores y de ahí la confusión. Por cierto, lo intenté con volátil y funcionó como se mencionó. –

0

Mi conjetura sería que declarar w const permite al compilador realizar optimizaciones más agresivas, como la incorporación del valor de w y las instrucciones de reordenamiento. Si parece que cambia w o no depende de qué optimizaciones se aplicaron en el caso preciso y no está bajo su control.

No se puede obligar w a ser totalmente const. El cons_cast debería ser una pista para el programador de que podrían estar haciendo algo sospechoso.

2

¿Por qué no puedes volver a unir la constante? Así que en lugar de

const int w = 10; 
int* wp = const_cast <int*> (&w); 
*wp = 20; 
// some code 

acaba de introducir los diferentes constante con el mismo nombre

const int w = 10; 
{ 
    const int w = 20; 
    // the same code 
} 

Si la "nueva" constante deberían depender de su propio valor, debe introducir otra constante (const int _w = w; const int w = _w * 2;). Las asignaciones innecesarias se optimizarán mediante el compilador, porque hemos visto que ha realizado dicha optimización, ya que es la razón por la que hizo su pregunta.

+0

Yuck. Esto podría funcionar, pero es feo. –

+1

Ugly es su 'const_cast's y el código de ensamblado, mientras que las constantes de volver a unir es una forma natural de trabajar con ellos. –

1

Aquí hay un repaso, debe tenerse en cuenta que esto está en C.Esta es una base engañosamente engañosa del uso de una variable o puntero usando la palabra clave const. Esto resalta la diferencia entre la variable de indicador foo y cómo el significado de la misma puede cambiar utilizando dicha palabra clave.

 
char const *foo; 

char * const foo; 

const char *foo; 

Las primeras y últimas declaraciones, hace que los datos apuntado por ‘foo’ sólo lectura, pero, puede cambiar la dirección a la que apunta ‘foo’, por ejemplo,

 
const *char foo; /* OR char const *foo */ 

char str[] = "Hello"; 

foo = &str[0]; /* OK! */ 

foo[1] = 'h'; /* BZZZZTTT! Compile Fails! */ 

La declaración media en lo anterior, hace que el puntero de sólo lectura, es decir, no se puede cambiar la dirección de los datos apuntado por 'foo'

 
char * const foo; 

char str[] = "Hello"; 

foo = &str[0]; /* BZZZZTTT! Compile Fails! */ 
+0

'const * char foo;' es un error –

+0

'char * const foo;' es un error en C++ (esta pregunta está etiquetada C++) - las variables 'const' deben tener un inicializador –

+0

@MM Wow 6 años después ... xD – t0mm13b

7

El código en el anterior ejemplo, se traduce en la siguiente ensamblador:

movl $10, 28(%esp) //const int i = 10; 
    leal 28(%esp), %eax //int* wp = const_cast <int*>(&i); 
    movl %eax, 24(%esp) //store the pointer on the stack 
    movl 24(%esp), %eax //place the value of wp in eax 
    movl $20, (%eax) //*wp = 20; - so all good until here 
    movl $10, 4(%esp) //place constant value 10 onto the the stack for use in printf 
    movl $.LC0, (%esp) // load string 
    call printf //call printf 

Debido a que el int original, me declararon constante, el compilador se reserva el derecho de utilizar º e valor literal en lugar del valor almacenado en la pila. Esto significa que el valor no se cambia y está atascado con el original 10.

La moraleja de la historia es que las constantes de tiempo de compilación deben permanecer constantes porque eso es lo que le está diciendo al compilador. La moraleja de la historia es que desechar la constness para cambiar una constante puede conducir a cosas malas.

2

No debe cambiar el valor de const. Hay una razón por la cual es const y tratar de cambiarlo probablemente resultará en errores. Si la const está almacenada en una sección de memoria de solo lectura, entonces obtendrás violaciones de acceso.

+1

Bastante, y sería mi primera reacción también. Pero en el mundo real, a veces tienes que "Hay una razón por la cual es const", supone, como mínimo, que el programador que originalmente lo hizo const sabía lo que estaba haciendo. –

+0

@John: Incluso en el mundo real no hay ninguna razón para cambiar un valor constante. Arregle el problema subyacente en lugar de meterse con él. –

0

Buena pregunta. Creo que la confusión proviene del hecho de que C++ usa la palabra clave 'const' para dos conceptos diferentes según el contexto. Estos conceptos son variables constantes y de solo lectura.

Cuando se puede calcular un valor de una variable 'const' durante la compilación, crea una constante verdadera. Las referencias a dicha constante se reemplazan por su valor cada vez que se utiliza. Es por eso que no hay una ubicación en la memoria que pueda modificarse para afectar a todos los lugares donde se usa. Es como usar #define.

Cuando el valor de una variable 'const' no se puede calcular durante la compilación, crea una variable de solo lectura. Tiene una ubicación en la memoria que contiene un valor, pero el compilador impone un comportamiento de solo lectura.

Cuestiones relacionadas