crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

> Когда применять const_cast
AXELman4ever
  опции профиля:
сообщение 24.9.2011, 2:20
Сообщение #1


Студент
*

Группа: Участник
Сообщений: 31
Регистрация: 22.9.2011
Пользователь №: 2902

Спасибо сказали: 0 раз(а)




Репутация:   0  


Всем добрый!

Пытаюсь понять принцип работы const_cast. Для интереса про-инициализировал значение (int) переменной в стеке, вместо того, чтобы создать на него указатель. После чего, загнал ссылку переменной и решил привести к типу pointer на int, дабы снять с переменной константность:

const int i = 5;
int *ptr = const_cast <int*> (&i);


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

И вот чему я был удивлен. Адрес, который хранит указатель и адрес ссылки - одинаковы, но значения у них разные:

qDebug() << "*ptr: "<< ptr << "-" << *ptr; // *ptr: 0x28ff10 - 6
qDebug() << "&i: "<< &i << "-" << i; // &i : 0x28ff10 - 5

Объясните пожалуйста, как так происходит? и почему const_cast нельзя вызвать для константных типов значений?

PS: Посоветуйте какую-нибудь легкодоступную для понимая книжечку по азам С++, если можно. Книги читать не люблю, но, так понимаю, без них никак. Заранее благодарен.

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
 
Начать новую тему
Ответов
Гость_D_*
сообщение 24.9.2011, 12:41
Сообщение #2





Гости








    


Вот вам ответ, почему так происходит

Код:
int main(int argc, char* argv[])
{
        const int i = 5;
        int *p = const_cast<int *>(&i);

        ++(*p);

        printf("&i: %d i:  %d\n", &i, i);
        printf("p:  %d *p: %d\n", p, *p);
        getchar();

        return 0;
}


А вот что мы увидем если компилировать его в ассемблерный код. Это только фрагмены:

            const int i = 5;                      ; валяется в стеке со смещением ebp-4
;
    ?debug L 5                                  ; ерунда какая-то
@1:
    mov       dword ptr [ebp-4],5      ; инициализируем i
;
;            int *p = (int *)(&i);                ; валяется в стеке со смещением ebp-8
;
    ?debug L 6
    lea       eax,dword ptr [ebp-4]    ; запишем в eax эффективный адрес двойного слова по адресу, записанному в стеке со
                                                                    ; смещением ebp-4
    mov       dword ptr [ebp-8],eax  ; инициализируем этим указатель p, который валяется в стеке со смещением ebp-8
;
;
;            ++(*p);                                  ; момент истины
;
    ?debug L 8                                  ; какая-то фигня
    mov       edx, dword ptr [ebp-8] ; поместим в edx то, что записано в стеке со смещением ebp-8, то есть p, в котором хранится
                                                                    ; адрес i
    inc       dword ptr [edx]                ; теперь взять и инкременировать то, что лежит по адресу записаному в edx. А в edx у нас
                                                                    ; валяется значение p инициализированное эффективным адресом того, что записаным в
                                                                    ; стеке ebp-4, которое и есть цифра 5.
                                                                    ; то есть теперь у нас *p == 6 и, следовательно, i == 6;

;            printf("&i: %d i:  %d\n", &i, i);
;
    ?debug L 10                                   ; это не интересно

    push      5                                        ; вот здесь ответ, сразу значение 5 вплевывает в стек (!!!!!!!!!!!!!!!!!!!!!!!!!!)
    lea       ecx,dword ptr [ebp-4]       ;  поместить в ecx эффективный адрес двойного слова лежащего в стеке со смещением
                                                                       ; [ ebp-4], то есть наш &i
    push      ecx                                    ; плюнуть это в стек
    push      offset s@                         ; строка форматирования для вызова printf, вплевываем адрес ее смещения в сегменте
                                                                       ; данных
    call      @_printf                              ; печатаем
    add       esp,12                               ; чистим стек
;
;            printf("p:  %d *p: %d\n", p, *p);
;
    ?debug L 11                                  ; далее выводится уже не константное значение, а значение того, что лежит по адресу *p
    mov       eax,dword ptr [ebp-8]    
    push      dword ptr [eax]
    push      dword ptr [ebp-8]
    push      offset s@+15
    call      @_printf
    add       esp,12


По русски это означает, что срабатывает оптимизация зависящая от реализации конкретного компилятора. Поскольку на этапе компиляции, здесь значение const i уже известно, компилятор при выводе его значения сразу подставляет число 5. При этом в ассемблерном коде видно, что при инкременте значение i действительно изменяется.
У Страуструпа написано, что подобного рода приведения создают ситуации в результате которых поведение константных объектов становится неопределенным

А еще, например, можно сделать так:
int main(int argc, char* argv[])
{
        const int *i = new int;
        int *p = const_cast<int *>(i);

        *p = 5;

        printf("i:  %d *i:  %d\n", i, *i);
        printf("p:  %d *p: %d\n", p, *p);
        getchar();

        delete i;

        return 0;
}

Тогда все будет уорректно. Поскольку значение константы на этапе компиляции здесь не известно.

Лёгких книжек по С++ не ищите. В плане понимания... мне очень нравится Философия С++ Брюса Эккеля. Совсем для начала можно Липпмана... у Эккеля в начале много абстрактного и исторического, поэтому может быть скучно. Но он хорош, он оперирует к размышлениям о языке, о его конструкциях и концепциях... кроме того у него большой опыт в преподавании С++. Со Страуструпа сразу начинать я бы не советовал, но прочесть тоже нужно.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме


Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 18.2.2025, 15:56