Почему const_cast удаляет constness для указателя, но не для указателя на const?
Я это понимаю const_cast
работает с указателями и ссылками.
Я предполагаю, что вклад в const_cast
должен быть указатель или ссылка. Я хочу знать, почему он не удаляет константность, если вход является указателем / ссылкой на const int
?
Следующий код работает как положено.
const_cast
с многоуровневыми указателямиint main() { using std::cout; #define endl '\n' const int * ip = new int(123); const int * ptr = ip; *const_cast<int*>(ptr) = 321; cout << "*ip: " << *ip << endl; // value of *ip is changed to 321 }
Но когда я пытаюсь указатель на
const int
или ссылка наconst int
значение не меняется.const_cast
со ссылкой на const intint main() { using std::cout; #define endl '\n' const int i = 123; const int & ri = i; const_cast<int&>(ri) = 321; cout << "i: " << i << endl; // value in 'i' is 123 }
const_cast
с указателем на const intint main() { using std::cout; #define endl '\n' const int i = 123; const int * ri = &i; *const_cast<int*>(ri) = 321; cout << "i: " << i << endl; // value in 'i' is 123 }
(1) работает, как ожидалось, но я не могу понять, почему (2) и (3) не работают так, как я думаю, хотя вклад в const_cast
это указатель / ссылка
Пожалуйста, помогите мне понять философию этого. Благодарю.
3 ответа
Есть два вида постоянства.
Константность объекта является неотъемлемым свойством объекта. Это не может быть изменено.
Подумайте о странице в печатной книге. Это может быть просмотрено как строка символов, и это не может быть изменено. Он говорит то, что говорит, и все тут. Так что это const string
,
Теперь подумайте о доске. На нем может быть что-то написано. Вы можете стереть это и написать что-то еще. Таким образом, доска неконстантна string
,
Другой вид константности - это указатель и эталонная константность. Эта константность не является неотъемлемым свойством указанного объекта, но является разрешением. Он говорит, что вы не можете изменять объект через этот указатель. В нем ничего не говорится о том, можно ли изменить сам объект.
Поэтому, если у вас есть константный указатель, вы не обязательно знаете, на что он действительно указывает. Может быть, это страница книги. Может быть, это доска. Указатель не говорит.
Теперь, если вы как-то знаете, что это действительно доска, вы можете быть противным и требовать разрешения, чтобы пойти дальше и изменить то, что написано на нем. Это то, что делает const_cast. Это дает вам разрешение на что-то сделать.
Что произойдет, если вам потребуется разрешение на изменение строки, и она окажется печатной страницей? Вы получаете свое разрешение, вы идете и стираете это... и... Что именно происходит, не определено. Возможно, ничего вообще. Возможно, отпечаток размазан, и вы не можете ни распознать оригинальную строку, ни написать что-либо сверху. Возможно, ваш мир взрывается на мелкие кусочки. Вы можете попробовать и увидеть, но нет никакой гарантии, что то же самое случится завтра.
(2) и (3) имеет тот же принцип, поэтому я буду говорить только о (2).
Линия
const_cast<int&>(ri) = 321;
имеет неопределенное поведение.
Вы не можете изменить const
объект в соответствии со стандартом, даже не с const_cast
, Если вы удалите const
из указателя / ссылки и изменить указанный / указанный объект, указанный / указанный объект не должен быть объявлен как const
на первом месте.
const_cast
должен использоваться только, когда у вас есть постоянный указатель на что-то по какой-то причине, и вы знаете, что что-то не объявлено как const
,
Изменение константы через const_cast
является неопределенным поведением.
Компилятор видит, что вы пытаетесь вывести постоянную переменную, знает, что она никогда не изменится, поэтому компилирует:
cout << "i: " << i << endl;
чтобы:
cout << "i: " << 123 << endl;
см.: https://godbolt.org/z/bYb0mx. С включенной оптимизацией он оптимизирует ваш код до печати 123: https://godbolt.org/z/4Ttlmj.
В конечном счете, компиляторы делают предположения для создания более быстрого / меньшего кода, если вы вводите области неопределенного поведения, некоторые из этих предположений могут быть неверными и приводить к неожиданным результатам.