tags:

views:

469

answers:

7

I am trying to change the value of a variable which is defined as int const as below.

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

The value of w didn't change and was 10 even after the assignment, though it shows as if both w and wp are pointing to the same memory location. But I am able to the change the value of w, if defined as below while declaring

int i = 10;
const int w = i;

If I change the declaration of i to make it const like in

const int i = 10;

The value of w doesn't change.

In the first case, how come the value of w didn't change, even though w and wp point to the same memory location [ that was my impression I get when I print their addresses ]

What difference it's to the compiler that it treats both the cases differently?

Is there a way to make sure that w doesn't lose constness, irrespective of the way it is defined?

+4  A: 

const_cast doesn't take away the const-ness of a variable as defined. If you were to pass a non-const variable by reference in to a method taking a const reference like void foo(const int& x) then you could use const_cast to modify the value of x within foo, but only if the variable you actually passed in was not const in the first place.

Dave
+7  A: 

This is one of the cases where a const cast is undefined, since the code was probably optimized such that w isn't really a variable and does not really exist in the compiled code.

Try the following:

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

Anyhow, I would not advise abusing const_cast like that.

rmn
The magic difference is the `volatile` keyword. Take that out and w=10 just like in Narendra's original pointer-based example.
Paul Stephenson
You are correct, the volatile qualifier is used to keep the compiler from optimizing w away.
rmn
I have tried the same on three different compilers [ Visual C++ Express Edition, g++ and Sun CC compiler ], on all three compilers the result was same. There was consistency in the results with all the compilers and hence the confusion. Btw, I tried with volatile and it worked as mentioned.
Narendra N
One of my colleague mentioned that a variable remains constant only when the value is known at the compile time. When defined as int i = 10; int const w = i; here as i is not const, we would be able to change it's value before the defintion of w, by reading the value from the user. if the value to a const variable is assigned with a literal or const variable, the value will be known at compile time and remains constant. May be the purpose of the const_cast is as commented by Chris Jester, to const_cast back and forth those which are created as non-const and not the other way
Narendra N
A: 

My guess would be that declaring w const allows the compiler to perform more aggressive optimizations such as inlining w's value and reordering instructions. Wether w appears to change or not depends on which optimizations were applied in the precise case and is not under your control.

You can't force w to be totally const. The cons_cast should be a hint to the programmer that they might be doing something fishy.

Zen
A: 

Why can't you just re-bind the constant? So instead of

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

just introduce the different constant with the same name

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

If the "new" constant should depend on its own value, you should introduce another constant (const int _w = w; const int w = _w * 2;). The unnecessary assignments will be optimized out by compiler--because we've seen it has done such optimisation, as it's the reason why you asked your question.

Pavel Shved
Yuck. This might work, but it's ugly.
Graeme Perrow
Ugly are your `const_cast`s and assembly code, while re-binding constants is a natural way to work with them.
Pavel Shved
+1  A: 
tommieb75
+4  A: 

The code in the above example translates into the following assembler:

    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

Because the original int i was declared constant, the compiler reserves the right to use the literal value instead of the value stored on the stack. This means that the value does not get changed and you are stuck with the original 10.

The moral of the story is compile time constants should remain constant because that is what you are telling the compiler. The moral of the story is that casting away constness in order to change a constant can lead to bad things.

doron
+2  A: 

You should not being changing the const value. There is a reason it is const and trying to change it will most likely just result in errors. If the const is stored in a read only memory section then you will get access violations.

Fair enough, and would be my first reaction as well. But in the real world, sometimes you gotta. "There is a reason it is const," assumes, at minimum, that the programmer who originally made it const knew what he was doing.
John Dibling
@John: Even in the real world there is no reason to change a const value. Fix the underlying problem rather then mess around with it.
Martin York