Avi Shukron
Avi Shukron

Reputation: 6118

What is the result of the Reference Operator "&" on const variables?

I was asked how can a value of a const variable can be changed.

My my obvious answer was "pointers!" but I tried the next piece of code and I'm puzzled...

int main()
{
    const int x = 5;
    int *ptr = (int *)(&x); // "Cast away" the const-ness..
    cout << "Value at " << ptr << ":"<< (*ptr) <<endl;
    *ptr = 6;
    cout << "Now the value of "<< ptr << " is: " << (*ptr) <<endl;
    cout << "But the value of x is still " << x <<endl;
    return 0;
}

And the output was:

Value at <some address> :5
Now the value of <same address> is: 6
But the value of x is still 5

Now, I'm not sure exactly what is returned from '&x' but it's definitely not the actual address of x, since the value at x wasn't changed!

But on the over hand, ptr did contain the value of x at the beginning! So, what is it exactly?

EDIT compiled with VS2010

Upvotes: 7

Views: 377

Answers (5)

Felice Pollano
Felice Pollano

Reputation: 33252

Maybe you are experiencing a side effect of code optimization, try to run the same code by disabling all optimization, or check at the asm generated code. I guess the compiler is reusing the value it has in some registry along the function since he bet on the const, so even if you are actually changing the value, the changed value is not propagated properly. The reasons for that as Keith noticed in the comemnts, is that you are palying with an undefined behavior.

Upvotes: 1

celtschk
celtschk

Reputation: 19721

What is returned from &x is a pointer to const int (i.e. int const*). Now pointers are inded implemented as holding the address, but pointers are not addresses, and your example shows quite nicely why: The type of the pointer, even though not present at run time, still plays an important role.

In your case, you are casting away the const, and thus lying to the compiler "this pointer points to a non-const int". However the compiler knows from the declaration that the value of x cannot change (it was declared const), and makes freely use of that fact (and the standard allows it: Your attempt to change it through a pointer to non-const int is undefined behaviour and therefore the compiler is allowed to do anything).

Upvotes: 0

sepp2k
sepp2k

Reputation: 370112

Your program invokes undefined behavior (writing to a const variable through a pointer is undefined behavior), so anything might happen. That being said here's the most likely explanation why you get the behavior you see on your particular implementation:

When you do &x, you do get the address of x. When you do *ptr = 6, you do write 6 to x's memory location. However when you do cout << x, you don't actually read from x's memory location because your compiler optimized the code by replacing x with 5 here. Since x is const the compiler is allowed to do that since there is no legal C++ program in which doing so would change the program's behavior.

Upvotes: 15

Mysticial
Mysticial

Reputation: 471229

First of all, this behavior is undefined. That said, here's what's probably going on:

When you do this:

int *ptr = (int *)(&x);

The 5 is stored at some address at somewhere. That's why the pointer seems to work properly. (although casting away the const is still undefined behavior)

However, due to compiler optimizations x = 5 is just inlined as a literal in the final print statement. The compiler thinks it's safe because x is declared const.

cout << "But the value of x is still " << x <<endl;

That's why you print out the original value 5.

Upvotes: 2

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84159

Compiler caches x in a register, so the value in memory changes, but the last print-out is still the same. Check out generated assembly (compile with -s).

Upvotes: 2

Related Questions