Modificando uma const através de um ponteiro não-const

Estou um pouco confuso com o que aconteceu no seguinte código:

const int e = 2; int* w = ( int* ) &e; // (1) cast to remove const-ness *w = 5; // (2) cout << *w << endl; // (3) outputs 5 cout << e << endl; // (4) outputs 2 cout << "w = " << w << endl; // (5) w points to the address of e cout << "&e = " << &e << endl; 

Em (1), w aponta para o endereço de e. Em (2), esse valor foi alterado para 5. No entanto, quando os valores de * we são exibidos, seus valores são diferentes. Mas se você imprimir o valor de w pointer e & e, eles terão o mesmo valor / endereço.

Como e ainda continha 2, mesmo que fosse alterado para 5? Eles foram armazenados em um local separado? Ou temporário? Mas como é que o valor apontado por w ainda é o endereço de e?

Como eu disse no meu comentário, uma vez que você modificou o valor de const você está em terra de comportamento indefinido, então não faz muito sentido falar sobre o que está acontecendo. Mas que caralho..

 cout < < *w << endl; // (3) outputs 5 cout << e << endl; // (4) outputs 2 

Em um palpite, *w está sendo avaliado em tempo de execução, mas e está sendo tratado como uma constante de tempo de compilation

Eu suspeito que você esteja tropeçando no compilador. Não espera que você jogue truques sujos com e, então quando vir a linha:

 cout < < e << endl; 

Ele simplesmente insere o valor 2 em vez de procurar o valor real. Você pode verificar (ou desmentir) isso observando a desassembly do seu programa.

Eu estou supondo que o compilador otimizou a saída do valor. Veja que e é const (assim, não pode mudar – em teoria) e muda cout < < e << endl; para cout < < 2 << endl; . No entanto, e ainda tem que existir porque é usado por w , então corretamente pega seu endereço e modifica seu valor, mas você não vê isso no cout .

Moral da história - apenas declare as coisas quando você realmente quer ser const . Evitar a const não é uma boa ideia.

A única coisa em que consigo pensar é que o compilador tem alguma forma de otimizar o código de tal forma que quaisquer referências a e sejam substituídas por um valor de 2, mesmo que ele atribua memory para e

assim, em vigor (afeta?) a linha no comentário (4) é ‘otimizada’ para ser

 cout < < "2" << endln; 

Eu acho que o compilador usa o constness para otimizar a variável e inserir um valor fixo no código.

Isto é coberto pela seção [dcl.type.cv] / 4 do padrão C ++ 14 (padrões anteriores também tinham texto similar):

Exceto que qualquer membro da class declarado mutable pode ser modificado, qualquer tentativa de modificar um object const durante sua vida útil resulta em um comportamento indefinido.

e é um object const e *w = 5; tenta modificar esse object, portanto, o resultado é um comportamento indefinido .