Изменение const через неконстантный указатель - PullRequest
13 голосов
/ 24 марта 2010

Я немного запутался, что произошло в следующем коде:


const int e = 2;

int* w = ( int* ) &e;          // (1) cast to remove const-ness
*w = 5;                        // (2)

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

cout &lt&lt "w = " &lt&lt w &lt&lt endl;   // (5) w points to the address of e
cout &lt&lt "&e = " &lt&lt &e &lt&lt endl;

В (1) w указывает на адрес e. В (2) это значение было изменено на 5. Однако, когда отображались значения * w и e, их значения были другими. Но если вы печатаете значение указателя w и & e, они имеют одинаковое значение / адрес.

Как же так получилось, что e все еще содержало 2, даже если оно было изменено на 5? Хранились ли они в отдельном месте? Или временный? Но почему значение, обозначенное w, все еще является адресом e?

Ответы [ 6 ]

17 голосов
/ 24 марта 2010

Как я уже сказал в своем комментарии, после того, как вы изменили значение const, вы попадаете в неопределенную область поведения, поэтому нет смысла говорить о том, что происходит. Но какого черта ..

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

По предположению, *w оценивается во время выполнения, но e рассматривается как постоянная времени компиляции

8 голосов
/ 24 марта 2010

Я подозреваю, что вы запускаете компилятор. Он не ожидает, что вы будете играть грязные трюки с e, поэтому, когда он видит строку:

cout << e << endl;

Он просто вставляет значение 2 вместо поиска фактического значения. Вы можете проверить (или опровергнуть) это, взглянув на разборку вашей программы.

4 голосов
/ 24 марта 2010

Я предполагаю, что компилятор оптимизировал вывод значения. Он видит, что e является постоянным (то есть, теоретически это не может измениться) и изменяется cout << e << endl; на cout << 2 << endl;. Однако e все еще должен существовать, потому что он используется w, поэтому w правильно берет свой адрес и изменяет его значение, но вы не видите этого в cout.

Мораль истории - объявляйте вещи const только тогда, когда вы действительно хотите быть const. Отбрасывать const Несс не очень хорошая идея.

3 голосов
/ 24 марта 2010

Единственное, о чем я могу думать, это то, что компилятор оптимизировал код таким образом, что любые ссылки на e заменяются значением 2, даже если он назначает память для e

так что в действительности (влияет?) Строка в комментарии (4) 'оптимизирована' до

cout << "2" << endln;
2 голосов
/ 24 марта 2010

Я думаю, компилятор использует константу для оптимизации переменной и вставки фиксированного значения в код.

1 голос
/ 04 мая 2017

Это описано в разделе [dcl.type.cv] / 4 стандарта C ++ 14 (более ранние стандарты также имели похожий текст):

За исключением того, что любой член класса, объявленный mutable, может быть изменен, любая попытка изменить объект const в течение срока его службы приводит к неопределенному поведению.

e является константным объектом, и *w = 5; пытается изменить этот объект, поэтому в результате получается неопределенное поведение .

...