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

Discussion in 'C++' started by CoolPint, Jul 22, 2004.

  1. CoolPint

    CoolPint Guest

    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!
    CoolPint, Jul 22, 2004
    #1
    1. Advertising

  2. Re: Can I modify a constant variable through a pointer obtained fromconst_cast?

    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_.
    Victor Bazarov, Jul 22, 2004
    #2
    1. Advertising

  3. CoolPint

    Andre Kostur Guest

    (CoolPint) wrote in
    news::

    > 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...).
    Andre Kostur, Jul 22, 2004
    #3
  4. CoolPint

    Siemel Naran Guest

    "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.
    Siemel Naran, Jul 22, 2004
    #4
  5. CoolPint

    Siemel Naran Guest

    "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;
    Siemel Naran, Jul 22, 2004
    #5
  6. Re: Can I modify a constant variable through a pointer obtained fromconst_cast?

    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
    Victor Bazarov, Jul 22, 2004
    #6
  7. CoolPint

    JKop Guest

    Siemel Naran posted:

    > const_cast is only garaunteed to work when the original

    object was
    > const.


    Could you please elborate on that?


    -JKop
    JKop, Jul 22, 2004
    #7
  8. CoolPint

    JKop Guest

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


    -JKop
    JKop, Jul 22, 2004
    #8
  9. CoolPint

    Andre Kostur Guest

    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)
    Andre Kostur, Jul 22, 2004
    #9
  10. CoolPint

    Ali Cehreli Guest

    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
    Ali Cehreli, Jul 22, 2004
    #10
  11. CoolPint

    JKop Guest

    It seems to me that C++ makes too many allowances for C's
    faults. For instance:

    char* blah = "JKop";
    blah[2] = 't';

    Undefined behaviour. But we wouldn't have this problem in
    the first place if that didn't compile.

    The next "version" of C++ should be "C++ without the C
    bullshit".

    -JKop
    JKop, Jul 22, 2004
    #11
  12. "Siemel Naran" <> wrote in message
    news:LgRLc.123119$...

    > > > const int i = 0;


    > 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);


    No, because this use of const_cast yields undefined behavior, which means
    that the compiler is permitted to do as it pleases.
    Andrew Koenig, Jul 22, 2004
    #12
  13. "JKop" <> wrote in message
    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.


    Here is an example of a use of const_cast that is well defined:

    void f()
    {
    int x;
    const int* p = &x;
    int* q = const_cast<int*>(p);
    *q = 42;
    }
    Andrew Koenig, Jul 22, 2004
    #13
  14. CoolPint

    Andre Kostur Guest

    JKop <> wrote in news:8OTLc.5288$:

    >
    > It seems to me that C++ makes too many allowances for C's
    > faults. For instance:
    >
    > char* blah = "JKop";
    > blah[2] = 't';
    >
    > Undefined behaviour. But we wouldn't have this problem in
    > the first place if that didn't compile.
    >
    > The next "version" of C++ should be "C++ without the C
    > bullshit".


    You're in the wrong place for that argument. You want to be over in
    comp.std.c++
    Andre Kostur, Jul 22, 2004
    #14
  15. CoolPint

    Siemel Naran Guest

    "Ali Cehreli" <> wrote in message
    > 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.


    Above "const" should be "non-const". Sorry for typo.
    Siemel Naran, Jul 23, 2004
    #15
  16. CoolPint

    Siemel Naran Guest

    "Andre Kostur" <> wrote in message

    > 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.


    This is a good example. Another uage is to implement the non-const function
    in terms of the const one.

    const X::value_type& X::get(int i) const {
    // lots of code
    };

    inline
    X::value_type& X::get(int i) {
    const X * cthis = this;
    return const_cast<value_type&>(cthis->get());
    };
    Siemel Naran, Jul 23, 2004
    #16
  17. CoolPint

    JKop Guest

    Siemel Naran posted:

    >> Since fn is documented to not change the passed in data,

    this is safe
    >> and legal.

    >
    > This is a good example. Another uage is to implement the

    non-const
    > function in terms of the const one.
    >
    > const X::value_type& X::get(int i) const {
    > // lots of code
    > };
    >
    > inline
    > X::value_type& X::get(int i) {
    > const X * cthis = this;
    > return const_cast<value_type&>(cthis->get());
    > };



    Since these functions will have extern "C" in front of
    them, the linker won't know anything about the arguments to
    it, whether or not they'll be const. Why doesn't one just
    change the header file and stick in "const" where
    appropriate?

    -JKop
    JKop, Jul 23, 2004
    #17
  18. Re: Can I modify a constant variable through a pointer obtained fromconst_cast?

    JKop wrote:
    >
    > Siemel Naran posted:
    >
    > >> Since fn is documented to not change the passed in data,

    > this is safe
    > >> and legal.

    > >
    > > This is a good example. Another uage is to implement the

    > non-const
    > > function in terms of the const one.
    > >
    > > const X::value_type& X::get(int i) const {
    > > // lots of code
    > > };
    > >
    > > inline
    > > X::value_type& X::get(int i) {
    > > const X * cthis = this;
    > > return const_cast<value_type&>(cthis->get());
    > > };

    >
    > Since these functions will have extern "C" in front of
    > them, the linker won't know anything about the arguments to
    > it, whether or not they'll be const. Why doesn't one just
    > change the header file and stick in "const" where
    > appropriate?


    If it's one of your own headers, then this is surely the way to go.
    But often you don't have that luxary. Eg. You bought a library
    and the header came with that library. Sure, you can change the header
    but this gets tedious very fast, when the next update of that library
    arives.


    --
    Karl Heinz Buchegger
    Karl Heinz Buchegger, Jul 23, 2004
    #18
  19. CoolPint

    Siemel Naran Guest

    "JKop" <> wrote in message news:p%5Mc.5337
    > Siemel Naran posted:


    > > This is a good example. Another uage is to implement the

    > non-const
    > > function in terms of the const one.
    > >
    > > const X::value_type& X::get(int i) const {
    > > // lots of code
    > > };
    > >
    > > inline
    > > X::value_type& X::get(int i) {
    > > const X * cthis = this;
    > > return const_cast<value_type&>(cthis->get());
    > > };

    >
    >
    > Since these functions will have extern "C" in front of
    > them, the linker won't know anything about the arguments to
    > it, whether or not they'll be const. Why doesn't one just
    > change the header file and stick in "const" where
    > appropriate?


    My example is valid C++, where you implement both a const and non-const
    function, like vector<T>::eek:perator[](size_type) comes in both flavors.
    Extern has nothing to do with it.
    Siemel Naran, Jul 23, 2004
    #19
  20. CoolPint

    Siemel Naran Guest

    "JKop" <> wrote in message 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.


    Another use of const_cast, which seems ok to me, is in my matrix code.

    There is a class matrix<T>

    It has const and non-const functions to get a row
    typename matrix<T>::row_t matrix<T>::row(int i);
    typename matrix<T>::const_row_t matrix<T>::row(int i) const;

    The nested class matrix<T>::row_t is public, but its constructor is private,
    and only the matrix<T>::row(int) functions can create instances of row_t and
    const_row_t objects.

    There is a function to swap two rows. Ordinarily, this function would be
    defined as
    void matrix<T>::swap(row_t&, row_t&);
    The swap function changes both the matrix as well as the function arguments
    by making them point to the new rows.

    But because I want the user to be able to say
    m.swap(m.row(1), m.row(2));

    the swap function is
    void matrix<T>::swap(const row_t&, const row_t&);

    In the body of the swap function I cast away const of the function
    arguments. This is OK because the original row_t object, created in
    matrix<T>::row(int), was created as not const.
    Siemel Naran, Jul 26, 2004
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Immortal Nephi
    Replies:
    2
    Views:
    566
    Eric Pruneau
    Jul 1, 2008
  2. Qi
    Replies:
    11
    Views:
    1,166
    Narinder
    Jul 12, 2011
  3. emrefan
    Replies:
    4
    Views:
    360
    emrefan
    Jun 5, 2007
  4. Replies:
    2
    Views:
    246
  5. G G
    Replies:
    3
    Views:
    91
    Ben Bacarisse
    Apr 20, 2014
Loading...

Share This Page