Почему const_cast удаляет constness для указателя, но не для указателя на const? - PullRequest
0 голосов
/ 31 августа 2018

Я понимаю, что const_cast работает с указателями и ссылками.

Я предполагаю, что входные данные для const_cast должны быть указателем или ссылкой. Я хочу знать, почему он не удаляет константность, если вход является указателем / ссылкой на const int?

Следующий код работает как положено.

  1. 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, значение, похоже, не меняется.

  2. const_cast со ссылкой на const int

    int 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
    }
    
  3. const_cast с указателем на const int

    int 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 ]

0 голосов
/ 31 августа 2018

Изменение константы с помощью const_cast - неопределенное поведение.

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

cout << "i: " << i << endl;

до:

cout << "i: " << 123 << endl;

см .: https://godbolt.org/z/bYb0mx. С включенной оптимизацией он оптимизирует ваш код до простой печати 123: https://godbolt.org/z/4Ttlmj.

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

0 голосов
/ 31 августа 2018

Есть два вида постоянства.

Константность объекта является неотъемлемым свойством объекта. Это не может быть изменено.

Подумайте о странице в печатной книге. Его можно рассматривать как строку символов, и его нельзя изменить. Это говорит то, что говорит, и все тут. Так что это const string.

Теперь подумайте о доске. На нем может быть что-то написано. Вы можете стереть это и написать что-то еще. Таким образом, доска неконстантна string.

Другим видом константности является указатель и эталонная константность. Эта константность не является неотъемлемым свойством указываемого объекта, но разрешение . Он говорит, что вы не можете изменять объект через этот указатель . В нем ничего не говорится о том, можно ли изменить сам объект.

Так что, если у вас есть константный указатель, вы не обязательно знаете, на что он действительно указывает. Может быть, это страница книги. Может быть, это доска. Указатель не сообщает.

Теперь, если вы как-то знаете, что это действительно доска, вы можете быть противным и требовать разрешения пойти дальше и изменить то, что написано на нем. Это то, что делает const_cast. Это дает вам разрешение на что-то.

Что произойдет, если вам потребуется разрешение на изменение строки, и она окажется напечатанной страницей? Вы получаете свое разрешение, вы идете дальше и стираете его ... и ... Что именно происходит, это undefined . Возможно, вообще ничего. Возможно, отпечаток размазан, и вы не можете ни распознать оригинальную строку, ни написать что-нибудь сверху. Возможно, ваш мир взрывается на мелкие кусочки. Вы можете попробовать и увидеть, но нет гарантии, что завтра произойдет то же самое.

0 голосов
/ 31 августа 2018

(2) и (3) имеют один и тот же принцип, поэтому я буду говорить только о (2).

Линия

const_cast<int&>(ri) = 321;

имеет неопределенное поведение.

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

const_cast следует использовать только в том случае, если по какой-то причине у вас есть постоянный указатель на что-то, и вы знаете, что что-то не объявлено как const.

...