2010-03-24 22 views
12

jestem trochę zdezorientowany co się stało w poniższym kodzie:Modyfikacja przez const const wskaźnik


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; 

W (1), białe punkty na adres e. W (2) wartość ta została zmieniona na 5. Jednakże, gdy wyświetlane były wartości * w i e, ich wartości są różne. Ale jeśli drukujesz wartość wskaźnika w i & e, mają one tę samą wartość/adres.

Jak to możliwe, że nadal zawiera 2, nawet jeśli zostało zmienione na 5? Czy były przechowywane w oddzielnej lokalizacji? A może tymczasowy? Ale dlaczego wartością wskazywaną przez w wciąż jest adres e?

+15

Masz nieokreślone zachowanie - wszystko może się zdarzyć. –

+0

Mój umysł jest zbyt zmęczony, aby zobaczyć, co się dzieje, ale możesz użyć do tego const_cast. Jeśli poprosiłeś o zrozumienie, co się dzieje, możesz zignorować ten komentarz. – erelender

+3

@erelender: Do tego można użyć 'const_cast', ale nie spowoduje to, że zachowanie będzie mniej nieokreślone. –

Odpowiedz

17

Jak już powiedziałem w swoim komentarzu, po zmodyfikowaniu wartości stałej jesteś w nieokreślonym stanie, więc nie ma sensu rozmawiać o tym, co się dzieje. Ale co do cholery ..

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

na oko, *w jest oceniany w czasie wykonywania, ale e jest traktowana jako kompilacji stałą

+0

Być może ... inna możliwość jest taka, że ​​kompilator zauważył "* w = 5" tuż przed i wstawił 5 w pierwszym wierszu zamiast * w – jpalecek

+0

Zgadzam się. Instancja const zainicjalizowana w zakresie będzie stała czasową kompilacji. –

+0

Czy to oznacza, że ​​po prostu nie ma sensu używać rzucania zmiennej stałej do wskaźnika niestałego, ponieważ modyfikowanie tego wskaźnika powoduje niezdefiniowane zachowanie? – jasonline

8

Podejrzewam, że potknął się kompilator. To nie spodziewa się, aby grać w brudnych sztuczek z e, więc gdy widzi linię:

cout << e << endl; 

to po prostu wstawia wartość 2 zamiast poszukiwać wartości rzeczywistej. Możesz zweryfikować (lub obalić) to, patrząc na demontaż swojego programu.

+0

+1 za spelunkowanie w zespole –

2

Domyślam się, że kompilator używa stałej do optymalizacji zmiennej i wstawienia do kodu wartości stałej.

3

Jedyną rzeczą, którą mogę pomyśleć, to kompilator ma jakiś sposób zoptymalizowany kod w taki sposób, że wszelkie odniesienia do e otrzymują o wartości 2, mimo że przydziela pamięć dla e

więc w efekcie (u?) linii w komentarzu (4) jest „zoptymalizowany” być

cout << "2" << endln; 
4

Zgaduję, że kompilator został zoptymalizowany wyjście wartość. Widzi, że e jest const (więc nie może się zmienić - teoretycznie) i zmienia cout << e << endl; na cout << 2 << endl;. Jednak nadal musi istnieć e, ponieważ jest używany przez w, więc w poprawnie przyjmuje swój adres i modyfikuje jego wartość, ale nie widzisz tego w cout.

Morał z opowiadania - tylko zadeklaruj rzeczy const, kiedy faktycznie chcesz być const. Odrzucanie const ness nie jest dobrym pomysłem.

1

ten jest objęty sekcji [dcl.type.cv]/4 standardu C++ 14 (wcześniej miał podobny tekst normy zbyt):

wyjątkiem tego, że każdy członek klasy zadeklarowane mutable mogą być modyfikowane, wszelkie próby modyfikowania const obiektu podczas jego wyników życia w niezdefiniowanej zachowań.

e jest const obiektu i *w = 5; próby modyfikacji tego obiektu, w związku z tym wynikiem jest undefined behavior.

Powiązane problemy