7

Here is my problem, the problem is in comments

const int a = 5;
const_cast<int&>(a)=7; //throw over const attribute in a,and assign to 7
std::cout<<a<<std::endl; //why still out put 5!!!!!!!!!!

Who can tell me why, and some books account these problems to recommend ? Thanks!

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Ryan_Liu
  • 269
  • 4
  • 9
  • 6
    It's undefined behaviour. It can do as it will. View the compiler's output code. It's probably just `std::cout << 5 << std::endl;`. – chris Dec 16 '13 at 03:15
  • 2
    You are lying to your compiler about the `const` being non-const. Compilers have nasty ways of getting back at you for not being honest with them ;-) (the official name for compilers hitting you back is "undefined behavior"). – Sergey Kalinichenko Dec 16 '13 at 03:21
  • But in , the author uses something like that: se is a set in some implement where the key of set is const,Emp::iterator i = se.find(...);... const_cast(*i).setValue(someValue);Why it can work? – Ryan_Liu Dec 16 '13 at 03:31
  • @Ryan_Liu could you paste the full example of the Effective STL example at the bottom of your question above? It's hard to tell you why it is (presumably) valid without the full context... – Jeff Dec 16 '13 at 03:37
  • 1
    @Ryan_Liu For the Effective STL question, it is not undefined behaviour if you are const_casting away the const on something that you know isn't actually const (in this case, the content of a container node). – Andre Kostur Dec 16 '13 at 06:44
  • It reminds me a question that I asked some time ago: http://stackoverflow.com/questions/16668656/explanation-of-the-ub-while-changing-data – PaperBirdMaster Dec 16 '13 at 10:35

3 Answers3

12

As-written the way you're doing this is undefined behavior. If you wanted to see the effects of const_cast<> in a defined manner:

int a = 5;                  // note: not const. regular object.
const int& cref = a;        // const-reference to same object.
cref = 7;                   // illegal. cref is a const reference.
const_cast<int&>(cref) = 7; // legal. the original object a is not const.

The only reason this is defined behavior is due to the non-const nature of the original variable, a. You cannot take an outright-const object and simply cast away the const-ness, which is what your posted code did. (at least as it has been explained to me on several occasions).

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • 1
    So it is said, when a compiler comes across a const value such as: const int a; The compiler can sometimes store that value in ROM which can never be modified for the life of the program. For this reason casting away const on a value that is declared const at its creation is undefined behavior. Calling a non-const value const at some later point in time allows the compiler to enforce that for a portion of the program the value will not change. These values can have their const-ness cast away in a defined manner, but it is often a sign of poor design when such a cast is necessary. – YoungJohn Dec 16 '13 at 19:12
4

The draft C++ standard section 7.1.6.1 The cv-qualifiers paragraph 4 says:

[...]any attempt to modify a const object during its lifetime (3.8) results in undefined behavior

So any behavior is possible but you should not be doing this and you definitely can not rely on this behavior. Of course const_cast does have valid uses as the accepted answer in Is const_cast safe? says:

const_cast is safe only if you're casting a variable that was originally non-const.[...]

We can see one way the results you are seeing can happen from this live example that gcc 4.8.1 without any optimization is just using the value 5 instead of reading the current value:

movl    $7, (%rax)
movl    $5, %esi
movl    $_ZSt4cout, %edi

in the non const case we will see something like this:

movl    $7, -4(%rbp)
movl    -4(%rbp), %eax
movl    %eax, %esi
movl    $_ZSt4cout, %edi
Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
2

The compiler is cheating you, since this (edit: the way you used it above exactly.) is explicitly undefined behavior. When it sees the a constant defined in the same scope as the cout statement, it's not bothering to even look at memory, most likely.

You could make a more contrived example to fool your compiler, but the following modification gives me the results you want in gcc at least:

volatile const int a = 5;

To clarify, not all const_cast usage is undefined behavior, see WhozCraig's example.

Jeff
  • 3,475
  • 4
  • 26
  • 35
  • But in , the author uses something like that: se is a set in some implement where the key of set is const,Emp::iterator i = se.find(...);... const_cast(*i).setValue();Why it can work? – Ryan_Liu Dec 16 '13 at 03:25
  • 1
    The compiler is cheating the programmer? I would say it's the other way around. ;) – Jim Buck Dec 16 '13 at 03:25
  • 1
    @Ryan_Liu There are well-known patterns for writing const methods (i.e., methods that won't modify non-mutable members) that avoid code duplication with the non-const version by judicious const_cast usage. Is that what's happening? – Jeff Dec 16 '13 at 03:33
  • @Jim No, man, the programmer is always right, right? :) – Jeff Dec 16 '13 at 03:34
  • Using volatile may change the apparent behavior but it is still undefined behavior to modify const variable. – Shafik Yaghmour Dec 16 '13 at 03:37
  • @Shafik Good point, but I've been assuming that he's trying to muddle around intentionally in undefined behavior, which might be a mistake. He's more likely misunderstanding the structure of the examples he's reading elsewhere as being equivalent to what he has above. – Jeff Dec 16 '13 at 03:41
  • The programmer is always right in the same sense that "the customer is always right". Umm, I'll leave it at that. :) – Jim Buck Dec 16 '13 at 03:42