2010-03-24 5 views
12

Ich bin ein wenig verwirrt, was in den folgenden Code passiert:eine const durch einen nicht konstanten Zeiger Ändern


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), w zeigt auf die Adresse von e. In (2) wurde dieser Wert auf 5 geändert. Wenn jedoch die Werte von * w und e angezeigt wurden, sind ihre Werte unterschiedlich. Aber wenn Sie den Wert von w Zeiger und & e drucken, haben sie den gleichen Wert/Adresse.

Wie kommt e noch 2 enthalten ist, auch wenn es bis zu 5 geändert wurde? Wurden sie an einem anderen Ort aufbewahrt? Oder ein temporäres? Aber warum ist der Wert von w immer noch die Adresse von e?

+15

Sie sind in undefiniert Verhalten Land - alles kann passieren. –

+0

Mein Verstand ist zu müde, um zu sehen, was passiert, aber Sie können const_cast dafür verwenden. Wenn Sie gefragt werden, was gerade passiert, können Sie diesen Kommentar ignorieren. – erelender

+3

@erelender: Sie könnten 'const_cast' dafür verwenden, aber es würde das Verhalten nicht weniger undefiniert machen. –

Antwort

17

Wie gesagt ich in meinem Kommentar, sobald Sie den const Wert, den Sie in undefiniertem Verhalten Land sind geändert, es macht so keinen Sinn, darüber zu sprechen, was geschieht. Aber was soll ..

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

Bei einer Vermutung wird *w zur Laufzeit ausgewertet werden, aber e als Kompilierung behandelt wird konstant

+0

Vielleicht ... andere Möglichkeit ist, dass der Compiler bemerkt "* w = 5" kurz vor und eingefügt 5 in der ersten Zeile anstelle von * w – jpalecek

+0

stimme ich zu. Ein const int, der im Gültigkeitsbereich initialisiert wird, ist eine Kompilierzeitkonstante. –

+0

Bedeutet das, dass es einfach keinen Sinn hat, eine const-Variable in einen nichtkonstanten Zeiger zu transformieren, da die Änderung durch diesen Zeiger zu undefiniertem Verhalten führt? – jasonline

8

Ich vermute, dass Sie die Compiler Stolpern sind. Es muss nicht erwarten, dass Sie schmutzige Tricks mit e zu spielen, so dass, wenn sie sieht die Zeile:

cout << e << endl; 

es einfach den Wert fügt 2 statt für den tatsächlichen Wert suchen. Sie können dies überprüfen oder widerlegen, indem Sie sich die Demontage Ihres Programms ansehen.

+0

+1 für Spelunking in Assembly –

2

Ich denke, die Compiler die Konstantheit verwendet die Variable zu optimieren und einen festen Wert in den Code einzufügen.

3

Das einzige, was ich denken kann, ist der Compiler einige hat, wie der Code so optimiert, dass alle Verweise auf E mit einem Wert von 2 ersetzt werden, obwohl es

so in der Tat für e-Speicher zuweist (auswirken?), um die Linie zu Kommentar (4) ‚optimiert‘

sein
cout << "2" << endln; 
4

ich vermute, dass der Compiler den Wert Ausgabe optimiert. Es sieht, dass e ist const (so kann es nicht ändern - in der Theorie) und ändert sich cout << e << endl; zu cout << 2 << endl;. Allerdings hat e noch existieren, weil sie von w verwendet wird, so w nimmt richtig seine Adresse und ändert seinen Wert, aber Sie sehen nicht, dass in der cout.

Moral der Geschichte - nur Dinge zu deklarieren const, wenn Sie eigentlich const sein wollen. const wegwerfen ist keine gute Idee.

1

Dies wird durch Abschnitt behandelt [dcl.type.cv]/4 der 14 Standard C++ (früher Standards hatte zu ähnlichen Text):

Abgesehen davon, dass jeder Teilnehmer, erklärt mutable modifiziert werden kann, jeden Versuch, ein const Objekt während seiner Lebensdauer führt zu undefinierten Verhalten zu ändern.

e ist ein const Objekt und *w = 5; Versuche, das Objekt zu ändern, damit das Ergebnis undefined behavior ist.