3

I know that using const_cast is generally bad idea, but I was playing around with it and I came across a weird behaviour, where:

Two pointers have the same address value, yet when de-referenced, give different data values.

Does anyone have an explanation for this?

Code

#include <iostream>

int main()
{
    const int M = 10;

    int* MPtr = const_cast<int*>(&M);

    (*MPtr)++;

    std::cout << "MPtr = " << MPtr << "   (*MPtr) = " << (*MPtr) << std::endl;
    std::cout << "  &M = " << &M << "         M = " << M << std::endl;
}

Output

MPtr = 0x7fff9b4b6ce0   (*MPtr) = 11
  &M = 0x7fff9b4b6ce0         M = 10
MGA
  • 1,658
  • 15
  • 28

2 Answers2

5

The program has undefined bahaviour because you may not change a const object.

From the C++ Standard

4 Certain other operations are described in this International Standard as undefined (for example, the effect of attempting to modify a const object). [ Note: This International Standard imposes no requirements on the behavior of programs that contain undefined behavior. —end note ]

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 2
    In this case, since your `M` is const, the output line doesn't even bother checking what number is stored at its address. It's just a hardcoded "print 10", since you've allowed the compiler to assume that `M` will always be 10. – Sneftel Mar 13 '14 at 21:42
2

So, aside from the "it's undefined behaviour" (which it is), the compiler is perfectly fine to use the fact that M is a constant, thus won't change, in the evaluation of cout ... << M << ..., so can use an instruction that has the immediate value 10, instead of the actual value stored in the memory of M. (Of course, the standard will not say how this works, more than "it's undefined", and compilers are able to choose different solutions in different circumstances, etc, etc, so it's entirely possible that you'll get different results if you modify the code, use a different compiler, different version of compiler or the wind is blowing in a different direction).

Part of the tricky bit with "undefined behaviour" is that it includes things that are "perfectly what you may expect" as well as "nearly what you'd expect". The compiler could also decide to start tetris if it discovers this is what you are doing.

And yes, this is very much one of the reasons why you SHOULD NOT use const_cast. At the very least NOT on things that were originally const - it's OK if you have something along these lines:

int x;

void func(const int* p)
{
  ...
  int *q = const_cast<int *>(p);

  *q = 7;
}


...

 func(&x);

In this case, x is not actually const, it just becomes const when we pass it to func. Of course, the compiler may still assume that x is not changed in func, and thus you could have problems....

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • Or, at least, why you should only use `const_cast` on variables which are actually *not* const, but which you have a consted pointer to. – Sneftel Mar 13 '14 at 21:43
  • const_cast is a critical tool, and it exists for a reason. you just have to know what it is for in order to use it correctly. – shawn1874 Mar 13 '14 at 21:49
  • 1
    Of course it's there for a reason - language architects (most of the time, at least) don't just add features because they fancy it. However, I have managed to work in C++ for about 7 years, without every needing to use const_cast. A colleague of mine did at one point need to do that - because some function that was declared as `const` needed to modify a member variable, so casting `this` with a const-cast was the only way out (redefining the function would be a much worse solution). So, "shouldn't use" is fine by me. – Mats Petersson Mar 13 '14 at 22:04
  • 1
    @MatsPetersson Very good answer, cheers. Just FYI, there is a keyword that does specifically what your colleague needed: declare the member as "mutable". – MGA Mar 13 '14 at 22:28
  • @mga: Yes, that would also be a possible option, but for some reason that wasn't possible - I think because basically "the original class definition can't be changed". It's about 4 years since I worked on that project, and it wasn't me doing that particular work (but I do remember the solution being "const_cast"). – Mats Petersson Mar 13 '14 at 22:31