Изменение значения переменной const в С++
Я пытаюсь изменить значение переменной, которая определяется как int const, как показано ниже.
const int w = 10;
int* wp = const_cast <int*> (&w);
*wp = 20;
Значение w не изменилось и было равно 10 даже после назначения, хотя оно показывает, что оба w и wp указывают на одно и то же место памяти. Но я могу изменить значение w, если оно определено ниже, объявляя
int i = 10;
const int w = i;
Если я изменяю объявление i, чтобы сделать его const, как в
const int i = 10;
Значение w не изменяется.
В первом случае, как получилось, значение w не изменилось, хотя w и wp указывают на то же место в памяти [это было мое впечатление, которое я получаю, когда печатаю их адреса]
Какая разница с компилятором, что он рассматривает оба случая по-разному?
Есть ли способ убедиться, что w не потеряет константу, независимо от того, как она определена?
Ответы
Ответ 1
Это один из случаев, когда const const является undefined, поскольку код, вероятно, оптимизирован таким образом, что w не является действительно переменной и на самом деле не существует в скомпилированном коде.
Попробуйте следующее:
const volatile int w = 10;
int &wr = const_cast <int &> (w);
wr = 20;
std::cout << w << std::endl;
Во всяком случае, я бы не советовал злоупотреблять const_cast таким образом.
Ответ 2
В приведенном выше примере код преобразуется в следующий ассемблер:
movl $10, 28(%esp) //const int i = 10;
leal 28(%esp), %eax //int* wp = const_cast <int*>(&i);
movl %eax, 24(%esp) //store the pointer on the stack
movl 24(%esp), %eax //place the value of wp in eax
movl $20, (%eax) //*wp = 20; - so all good until here
movl $10, 4(%esp) //place constant value 10 onto the the stack for use in printf
movl $.LC0, (%esp) // load string
call printf //call printf
Поскольку исходный int я был объявлен константой, компилятор оставляет за собой право использовать значение буквального значения вместо значения, хранящегося в стеке. Это означает, что значение не изменяется, и вы застряли с оригиналом 10.
Мораль истории - это константы времени компиляции, которые должны оставаться постоянными, потому что это то, что вы говорите компилятору. Мораль этой истории заключается в том, что изгнание совести для изменения константы может привести к плохим вещам.
Ответ 3
const_cast
не отображает константу переменной, как определено. Если бы вы передали неконстантную переменную по ссылке в метод, принимающий константу, такую как void foo(const int& x)
, тогда вы могли бы использовать const_cast
для изменения значения x
внутри foo
, но только если переменная, которую вы на самом деле прошло, не было const в первую очередь.
Ответ 4
Почему вы не можете просто переписать константу? Поэтому вместо
const int w = 10;
int* wp = const_cast <int*> (&w);
*wp = 20;
// some code
просто введите другую константу с тем же именем
const int w = 10;
{
const int w = 20;
// the same code
}
Если "новая" константа должна зависеть от ее собственного значения, вы должны ввести другую константу (const int _w = w; const int w = _w * 2;
). Невозможные назначения будут оптимизированы компилятором, потому что мы видели, что он сделал такую оптимизацию, поскольку это причина, по которой вы задали свой вопрос.
Ответ 5
Вы не должны изменять значение const. Существует причина, по которой она const и пытается ее изменить, скорее всего, приведет к ошибкам. Если const хранится в разделе памяти только для чтения, вы получите нарушения доступа.
Ответ 6
Здесь переподготовка, следует отметить, что это в C. Это обманчиво основано на использовании переменной или указателя с использованием ключевого слова const
. Это подчеркивает разницу между переменной-указателем foo
и тем, как ее значение может измениться с помощью указанного ключевого слова.
char const *foo;
char * const foo;
const char *foo;
Первая и последняя декларации делают данные, на которые указывает "foo только для чтения", но вы можете изменить адрес, на который указывает "foo, например.
const *char foo; /* OR char const *foo */
char str[] = "Hello";
foo = &str[0]; /* OK! */
foo[1] = 'h'; /* BZZZZTTT! Compile Fails! */
Среднее объявление выше, делает указатель только для чтения, т.е. вы не можете изменить адрес данных, на которые указывает "foo
char * const foo;
char str[] = "Hello";
foo = &str[0]; /* BZZZZTTT! Compile Fails! */
Ответ 7
Мое предположение заключалось бы в том, что объявление w const позволяет компилятору выполнять более агрессивные оптимизации, такие как встраивание w-значений и инструкций переупорядочения. Wether w, похоже, изменится или не зависит от того, какие оптимизации были применены в точном случае и не под вашим контролем.
Вы не можете заставить w быть полностью const. Cons_cast должен быть подсказкой для программиста, что они могут делать что-то подозрительное.
Ответ 8
Хороший вопрос. Я думаю, что путаница исходит из того, что С++ использует ключевое слово "const" для двух разных концепций в зависимости от контекста. Эти понятия являются постоянными и переменными только для чтения.
Когда значение переменной const может быть вычислено во время компиляции, оно создает истинную константу. Ссылки на такую константу заменяются ее значением всякий раз, когда она используется. Вот почему в памяти нет места, которое можно изменить, чтобы повлиять на все места, где оно используется. Это похоже на #define.
Когда значение переменной const не может быть вычислено во время компиляции, оно создает переменную только для чтения. Он имеет место в памяти, которое содержит значение, но компилятор обеспечивает поведение, доступное только для чтения.