Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Can I modify a constant variable through a pointer obtained from const_cast?

Reply
Thread Tools

Can I modify a constant variable through a pointer obtained from const_cast?

 
 
CoolPint
Guest
Posts: n/a
 
      07-22-2004
While I was reading about const_cast, I got curious and wanted to know
if I could modify a constant variable through a pointer which has been
"const_cast"ed. Since the pointer would be pointing to the constant
variable and if I changed the value through the pointer, the constant
variable should have been modified. Well, that's what I thought until
I wrote the following and run it.

#include <iostream>
using std::cout;
using std::endl;
int main ()
{
const int i = 0;
int &j = const_cast<int&>(i);
j = 10; // I thought this would change i, but it didn't
cout << &i << endl; // &i and &j are same as I expected
cout << &j << endl;
cout << i << endl; // but i is still 0
cout << j << endl; // and j is 10!

int * p = const_cast<int *>(&i);
*p = 30; // I change i via p
cout << &i << endl; // I confirm that p is pointing to i!
cout << p << endl; // I confirm that p is pointing to i
cout << i << endl; // i is still 0!
cout << *p << endl; // how can *p be 30 then?

return 0;
}

I am very much confused. &i and &j are same, meaning they refer to the
same location. p is also pointing to the same location. But then how
can i still be 0 and j be 10 and i still be 0 and *p 30????

Is j allocated new memory space? Is p pointing to a new location?

Can anyone kindly help me figure out what is going on?

BTW, is what I am observing is standard behaviour or particular to my
compiler (g++ version 3.2.3)?

Thank you very much in advance!
 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      07-22-2004
CoolPint wrote:
> While I was reading about const_cast, I got curious and wanted to know
> if I could modify a constant variable through a pointer which has been
> "const_cast"ed.


Let me say this right away: you can modify it, but it leads to undefined
behaviour. Once we established that, all other things are speculation,
at best.

> Since the pointer would be pointing to the constant
> variable and if I changed the value through the pointer, the constant
> variable should have been modified. Well, that's what I thought until
> I wrote the following and run it.
>
> #include <iostream>
> using std::cout;
> using std::endl;
> int main ()
> {
> const int i = 0;


Declaring a const int object does not necessarily allocate any memory
for it. Just so we're clear on that. The compiler is free to use
the actual value of the const given to it at the moment of declaration
instead of the object in memory (which, incidentally, may or may not
exist).

> int &j = const_cast<int&>(i);


So far, so good.

> j = 10; // I thought this would change i, but it didn't


It did. Or it didn't. Or it did, but then changed it back unbeknownst
to you. Anything can happen. No guarantees whatsoever. You broke your
own promise to the compiler: 'i' is constant. You attempted to change
it. The compiler (and the code produced by it) is not obligated to do
anything predictable or meaningful, for that matter.

> cout << &i << endl; // &i and &j are same as I expected
> cout << &j << endl;
> cout << i << endl; // but i is still 0


Well, this is where the speculation begins. 'i' is not really 0 "still".
It has been changed. The _code_ however was created to simply use '0'
instead of 'i' for the statement above. The compiler is allowed to do
that. It optimises away memory access since you promised that the memory
is not going to be altered in any way.

> cout << j << endl; // and j is 10!
>
> int * p = const_cast<int *>(&i);
> *p = 30; // I change i via p


Another cause for undefined behaviour, right here. If all bets were off
before, now they are really REALLY off.

> cout << &i << endl; // I confirm that p is pointing to i!
> cout << p << endl; // I confirm that p is pointing to i
> cout << i << endl; // i is still 0!
> cout << *p << endl; // how can *p be 30 then?
>
> return 0;
> }
>
> I am very much confused. &i and &j are same, meaning they refer to the
> same location. p is also pointing to the same location. But then how
> can i still be 0 and j be 10 and i still be 0 and *p 30????
>
> Is j allocated new memory space? Is p pointing to a new location?
>
> Can anyone kindly help me figure out what is going on?


I hope I have. Ask more questions if you happen to have them.

>
> BTW, is what I am observing is standard behaviour or particular to my
> compiler (g++ version 3.2.3)?


Yes. And no. There is no standard behaviour. The Standard says that
the behaviour is _undefined_.
 
Reply With Quote
 
 
 
 
Andre Kostur
Guest
Posts: n/a
 
      07-22-2004
(CoolPint) wrote in
news: om:

> While I was reading about const_cast, I got curious and wanted to know
> if I could modify a constant variable through a pointer which has been
> "const_cast"ed. Since the pointer would be pointing to the constant
> variable and if I changed the value through the pointer, the constant
> variable should have been modified. Well, that's what I thought until
> I wrote the following and run it.


No. It is your responsibility to ensure that the object that you
const_cast away from really isn't a const object. Any attempt to modify
a const object, through whatever means you can find, is undefined
behaviour.

>


Some in-line comments which will make more sense with the explanation
below:

> #include <iostream>
> using std::cout;
> using std::endl;
> int main ()
> {
> const int i = 0;
> int &j = const_cast<int&>(i);


This refers to the variable i.

> j = 10; // I thought this would change i, but it didn't
> cout << &i << endl; // &i and &j are same as I expected


This has the address of the variable i.

> cout << &j << endl;
> cout << i << endl; // but i is still 0


Since i is declared as const, the compiler can remove the reference to i,
and rewrite this line to effectively be:

cout << 0 << endl;

> cout << j << endl; // and j is 10!


This refers to the variable i.

> int * p = const_cast<int *>(&i);
> *p = 30; // I change i via p
> cout << &i << endl; // I confirm that p is pointing to i!
> cout << p << endl; // I confirm that p is pointing to i
> cout << i << endl; // i is still 0!
> cout << *p << endl; // how can *p be 30 then?


Same logic as above.

>
> return 0;
> }
>
> I am very much confused. &i and &j are same, meaning they refer to the
> same location. p is also pointing to the same location. But then how
> can i still be 0 and j be 10 and i still be 0 and *p 30????


Since you told the compiler that i is a const int 0, anyplace that i is
used, the compiler could optimize the variable access away and replace it
with a literal 0. When you took the address of i, it needs a memory
location, so the compiler is forced to allocate memory for it. (Side
question: if you never cause the address of i to be taken, even
implicitly, is the compiler required to reserve memory space for i, or
can it completely optimize the variable out of existance?)

> Is j allocated new memory space? Is p pointing to a new location?
>
> Can anyone kindly help me figure out what is going on?
>
> BTW, is what I am observing is standard behaviour or particular to my
> compiler (g++ version 3.2.3)?


It's undefined behaviour. The compiler could format your hard drive and
cause monkeys to fly out of your nether regions (OK, from a Standard
point of view it could...).
 
Reply With Quote
 
Siemel Naran
Guest
Posts: n/a
 
      07-22-2004
"CoolPint" <> wrote in message

> While I was reading about const_cast, I got curious and wanted to know
> if I could modify a constant variable through a pointer which has been
> "const_cast"ed. Since the pointer would be pointing to the constant
> variable and if I changed the value through the pointer, the constant
> variable should have been modified. Well, that's what I thought until
> I wrote the following and run it.


const_cast is only garaunteed to work when the original object was const.
If the original object is const, the compiler can substitute its values into
cout statements and so forth, so that even if you modify the variable
through a pointer the cout statement will print the original values. In
more complex examples, this replacing and evaluating of const variables at
compile time (I think it's called const folding) leads to great
optimizations. The compiler can also store the variable in read-only memory
as part of the compiled program, so that if you modify the variable through
a pointer the program will crash. In other cases, const_cast may work as
you want.

> {
> const int i = 0;
> int &j = const_cast<int&>(i);
> j = 10; // I thought this would change i, but it didn't
> cout << &i << endl; // &i and &j are same as I expected
> cout << &j << endl;
> cout << i << endl; // but i is still 0
> cout << j << endl; // and j is 10!


For cout << i, the compiler has substituted 0 into the cout statement as it
was originally const.


 
Reply With Quote
 
Siemel Naran
Guest
Posts: n/a
 
      07-22-2004
"Victor Bazarov" <> wrote in message news:O5RLc.47

> > #include <iostream>
> > using std::cout;
> > using std::endl;
> > int main ()
> > {
> > const int i = 0;

>
> Declaring a const int object does not necessarily allocate any memory
> for it. Just so we're clear on that. The compiler is free to use
> the actual value of the const given to it at the moment of declaration
> instead of the object in memory (which, incidentally, may or may not
> exist).


True, but if you take the address of the variable and use this address, the
compiler must allocate memory for it.

> > int &j = const_cast<int&>(i);


> > cout << &j << endl;



 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      07-22-2004
Siemel Naran wrote:
> "Victor Bazarov" <> wrote in message news:O5RLc.47
>
>
>>>#include <iostream>
>>>using std::cout;
>>>using std::endl;
>>>int main ()
>>>{
>>> const int i = 0;

>>
>>Declaring a const int object does not necessarily allocate any memory
>>for it. Just so we're clear on that. The compiler is free to use
>>the actual value of the const given to it at the moment of declaration
>>instead of the object in memory (which, incidentally, may or may not
>>exist).

>
>
> True, but if you take the address of the variable and use this address, the
> compiler must allocate memory for it.


Yes, but only for the purpose of taking its address. The compiler is
still free to use the value in any other instances without having to
go to the [allocated due to address taken] memory object.

V
 
Reply With Quote
 
JKop
Guest
Posts: n/a
 
      07-22-2004
Siemel Naran posted:

> const_cast is only garaunteed to work when the original

object was
> const.


Could you please elborate on that?


-JKop
 
Reply With Quote
 
JKop
Guest
Posts: n/a
 
      07-22-2004

Can some-one please explain to me why "const_cast" exists
at all? From what I can see it just produces undefined
behaviour.


-JKop
 
Reply With Quote
 
Andre Kostur
Guest
Posts: n/a
 
      07-22-2004
JKop <> wrote in news:V9SLc.5268$:

>
> Can some-one please explain to me why "const_cast" exists
> at all? From what I can see it just produces undefined
> behaviour.


You may be attempting to call legacy code which was not const-correct.
Let's assume that you have an old C library that has a function:

void fn(data * pdata);

And it is well-documented that fn() does not modify the data.



Now, in your C++ code you have:

void cfn(const data & somedata)
{
fn(&somedata);
}


OK, you _tried_ to have that, but the C++ compiler rejects it since you
are attempting to pass a const data* where the function signature is only
data*. However, this is legal and safe:

void cfn(const data & somedata)
{
fn(const_cast<data *>(&somedata));
}

Since fn is documented to not change the passed in data, this is safe and
legal.


I suppose a more relevent example would be:

int strcmp(char * cp1, char * cp2);

And try passing in:

std::string str1("abc"), str2("def");

std::cout << strcmp(str1.c_str(), str2.c_str());

(assume appropriate #include's)

 
Reply With Quote
 
Ali Cehreli
Guest
Posts: n/a
 
      07-22-2004
On Thu, 22 Jul 2004 09:43:09 -0700, JKop wrote:

> Siemel Naran posted:
>
>> const_cast is only garaunteed to work when the original

> object was
>> const.


I don't think this is correct.

>
> Could you please elborate on that?


I suspect that Siemel Naran meant this: Taking away const by a
const_cast is guaranteed to work only if the original object was
non-const to begin with.

It is undefined behavior to modify the original object if it was
initially defined as const.

Ali
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Can I include include a constant in a constant array? Fredxx VHDL 3 07-15-2009 07:39 AM
Can't modify constant item in scalar assignment emrefan Perl Misc 4 06-05-2007 03:21 AM
I 'VE JUST OBTAINED MY MCSD FRANCIS KAITANO MCSD 2 06-08-2005 03:32 PM
"Non-constant" constant can't be used as template argument Martin Magnusson C++ 2 10-08-2004 08:41 AM
pointer to member function and pointer to constant member function Fraser Ross C++ 4 08-14-2004 06:00 PM



Advertisments
 



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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57