2010-03-24 4 views
12

Sono un po 'confuso quello che è successo nel codice seguente:Modifica di un const tramite un puntatore non-const


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; 

In (1), punti w all'indirizzo di posta. In (2), tale valore è stato modificato in 5. Tuttavia, quando sono stati visualizzati i valori di * w ed e, i loro valori sono diversi. Ma se si stampa il valore del puntatore w e & e, hanno lo stesso valore/indirizzo.

Come mai e ancora contenuto 2, anche se è stato modificato in 5? Sono stati conservati in un luogo separato? O un temporaneo? Ma come mai il valore puntato da w è ancora l'indirizzo di e?

+15

Sei in una zona di comportamento non definito: può succedere di tutto. –

+0

La mia mente è troppo stanca per vedere cosa sta succedendo, ma puoi usare const_cast per questo. Se hai chiesto solo di capire cosa sta succedendo, puoi ignorare questo commento. – erelender

+3

@erelender: potresti usare 'const_cast' per questo, ma non renderebbe il comportamento meno indefinito. –

risposta

17

Come ho detto nel mio commento, una volta modificato il valore const ci si trova in un comportamento non definito, quindi non ha molto senso parlare di ciò che sta accadendo. Ma che diavolo ..

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

A occhio e croce, *w è in corso di valutazione in fase di esecuzione, ma e viene trattato come un momento della compilazione costante

+0

Forse ... altra possibilità è che il compilatore abbia notato "* w = 5" appena prima e inserito 5 nella prima riga invece di * w – jpalecek

+0

Accetto. Un const int inizializzato in scope sarà una costante di tempo di compilazione. –

+0

Significa che non è possibile utilizzare una variabile const per un puntatore non const, poiché la modifica tramite quel puntatore risulta in un comportamento non definito? – jasonline

8

Ho il sospetto che tu stia inciampando nel compilatore. Essa non si aspetta di giocare con trucchi sporchi e, in modo che quando si vede la linea:

cout << e << endl; 

Si inserisce semplicemente il valore 2 invece di cercare il valore effettivo. Puoi verificare (o smentire) questo osservando lo smontaggio del tuo programma.

+0

+1 per speleologia nell'assemblaggio –

2

Immagino che il compilatore usi la costanza per ottimizzare la variabile e inserire un valore fisso nel codice.

3

L'unica cosa che mi viene in mente è il compilatore ha in qualche modo ottimizzato il codice in modo tale che qualsiasi riferimento a e vengono sostituiti con un valore pari a 2, anche se assegna la memoria per l'e

così in effetti (influenzare?) la linea di commento (4) è 'ottimizzato' essere

cout << "2" << endln; 
4

sto indovinando che il compilatore ha ottimizzato il valore di uscita. Vede che e è const (quindi, non può cambiare - in teoria) e cambia cout << e << endl; a cout << 2 << endl;. Tuttavia, lo e deve ancora esistere perché è utilizzato da w, quindi w prende correttamente il suo indirizzo e modifica il suo valore, ma non lo vedi nello cout.

Morale della storia - solo dichiarare le cose const quando in realtà si desidera essere const. Gettare via const ness non è una buona idea.

1

Questo è coperto dalla sezione [dcl.type.cv]/4 dello standard C++ 14 (in precedenza avevano norme testo simile troppo):

Solo che ogni membro della classe dichiarata mutable possono essere modificati, qualsiasi tentativo di modificare un oggetto const durante i suoi risultati di durata nel comportamento indefinito.

e è un oggetto const, e *w = 5; i tentativi di modificare tale oggetto, quindi il risultato è undefined behavior.