const_cast

Hi,everyone. I have some doubts about using const_cast which I hope that you guys could help me to resolve.

Please take a look at the code below:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
int main()
{
    const int x=3;
    const int *y=&x;
    int *z=const_cast<int*>(y);
    cout<<&x<<" "<<y<<" "<<z<<endl;
    *z=4;
    cout<<x<<" "<<*y<<" "<<*z<<endl;
}


In the code above, it actually shows that int pointer z and const int pointer y both hold the same address and it's the address of a const int x, so here goes my first question: why an int pointer can hold the address of a const int?

Next, apparently I tried to change the value of x by assigning *y=4, but it generated a error, so I tried it again by assigning *z=4, and it worked out. However, if i printed x, *y and *z out here, I would find that the value of x didn't change and it's still 3, but both the values of *y and *z changed, which I can't make sense of. Since both y and z hold the address of x, if *z changes, presumably, both x and *y should change with *z.(at least that's what I think) Look for an explanation here.

Thanks everyone!
why an int pointer can hold the address of a const int?
Because you cast const away.

value of x didn't change
x is declared as const. That means its value will never change and compiler is free to optimise accesses to it.
By changing its value through const_cast, you produces an undefined behavior. On my machine you program crashes because it tries to write to the read only memory.
In most cases const_cast will provide undefined behavior. It should rarely be used and only on special occasions.
why an int pointer can hold the address of a const int?


There is an int(x) somewhere in memory. The const modifier makes it so you cannot change x, it is a const int and this is enforced by the compiler. There is another location in memory (y) that stores the address of x. y is a pointer to const int, and the compiler respects this. There is another location z that stores the same address. It's just the address of an int, by using const_cast you have told the compiler to treat the storage as int. As far as the compiler is concerned, y is the address of a const int and x is the address of an int. They just happen to be at the same location at the same time.

1
2
3
4
int a = 10;
const int *b = &a;
a = 24;
// *b = 15; -> illegal 


Even though, a is not const you cannot change it by using b. If a were const as below, then you cannot use a pointer to int, you have to use a pointer to const int.

1
2
3
const int a = 10;
// int *b = &a; -> illegal
// a = 24;  -> illegal 


I would find that the value of x didn't change

Because x is a built-in type, simple enough for the compiler to hold it in it's symbol table, and fold it in. So the compiler knows x is a const, and uses that value everywhere you directly refer to x, so when running your program, x is not directly read from storage, it has been folded in at compile time. Of coursethis does not apply to the pointers.

If x were a more complex object then the results would be different. To prove that x has indeed changed, try this sort of thing to prove it, after line 10, add:
1
2
	unsigned long cy = (unsigned long)(&x);
	cout << hex << cy << ":" << *((int *) cy) << endl;


Or this contrived example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
using namespace std;

class X
{
public:
	X(int r) : x(r) {}
	X operator=(int r)
	{
		x = r;
		return *this;
	}

	friend ostream &operator<<(ostream &os, const X& mx);
		
private:
	int x;
};

ostream &operator<<(ostream &os, const X& mx) { return os << mx.x; }

int main()
{
	const X x(3);
	const X *y=&x;
	X *z=const_cast<X*>(y);
	cout<<x<<" "<<*y<<" "<<*z<<endl;
	cout<<&x<<" "<<y<<" "<<z<<endl;
	*z=4;
	cout<<x<<" "<<*y<<" "<<*z<<endl;
	cout<<&x<<" "<<y<<" "<<z<<endl;
}
Topic archived. No new replies allowed.