const qualifier in C++

Тема в разделе "WASM.ZEN", создана пользователем green, 23 июн 2005.

  1. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Поскажите чем мотивирована ошибка компиляции сл. кода (VC++):
    Код (Text):
    1.  
    2. {
    3.     int **ppi;
    4.     const int **ppci;
    5.     ppci = ppi; // error C2440: '=' : cannot convert from 'int **' to 'const int **'
    6.                     //        Conversion loses qualifiers}
    7. }
    8.  


    Т.е. почему считается, что это преобразование "loses qualifiers" ?
     
  2. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    green





    int** и const int** - разные типы, потому и ошибка. Точно так же как если написать например int* и unsigned int*. Или вопрос был почему именно так сформулированно сообщение об ошибке?



    Кстати C-компилятор из MS Visual Studio компилирует пример без ошибок. Ошибку выдает компилятор C++.
     
  3. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Мне непонятно, почему компилятор считает, что преобразование
    Код (Text):
    1. int** -> const int**
    недопустимо.



    Ведь в таком случае
    Код (Text):
    1. int *pi;
    2. const int *pci = pi;


    никаких ошибок не возникает.
     
  4. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine


    Да, прошу прощения, забыл плюсы с названии топика.



    Кстати, это очень странно и похоже на баг в MS C-компиляторе - другой компилятор выдает в этом коде ошибку как в C так и в C++ режимах.
     
  5. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    А так?
    Код (Text):
    1.  
    2. typedef int ** ppint;
    3. ppint   ppi = 0;
    4. const ppint ppci = ppi;
    5.  
     
  6. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    S_T_A_S_
    Код (Text):
    1.  
    2. const ppint ppci
    3. эквивалентно
    4. int ** const ppci
    5.  
     
  7. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    green





    Потому что здесь приравнивание происходит на стадии инициализации. Все равно что написать скажем:



    int a=0xFFFFFFFF;

    unsigned int b=0xFFFFFFFF;



    Тоже проблем не будет, хотя интерпретируется число 0xFFFFFFFF в результате по разному.
     
  8. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Stiver
    Код (Text):
    1. int *pi;
    2. const int *pci;
    3. pci = pi;


    тоже компилится без ошибок
     
  9. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    Действительно компилируется, странно.. Ни у кого спецификации ANSI C++ случайно нет?
     
  10. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    Зато вот такое компилируется без ошибки:



    int c=1;

    const int* const cc=&c;

    const int* const *ppc=&cc;

    int**p;



    ppc=pp;



    Видимо внутри VC++ интерпретирует const int** как const int* const *. Баг компилятора?



    P.S.: Посмотрел, труп страуса пишет, что T* должно всегда без ошибки приводится к const T*, про двойные указатели не пишет ничего. Может это implementation specific?
     
  11. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    Stiver





    Тьфу! Как раз не интерпретирует. Так что это не баг, а действительно просто разные типы:

    int** - это указатель на (int*)

    const int** - это указатель на (const int*)

    и друг к другу они по умолчанию не приводятся.
     
  12. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Stiver



    Но ведь в этом случае
    Код (Text):
    1.     int **ppi;
    2.     const int * const *ppci;
    3.     ppci = ppi;
    4.  




    типы тем более разные, но тем не менее компилируется без ошибок.



    И странно, что компилятор MS выдает ошибку в C++ но не в C-режиме, а Comeau ругается в обоих режимах.

    Похоже на багу в компилере MS, т.к. никакой С++-специфики в таком коде вроде нет.



    Вопрос больше академический, но всё же интересно...
     
  13. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    green





    В этом случае действует правило, которое я процитировал выше:





    т.е. int** => int* const* => const int* const*

    Привести int** к const int** с помощью этого(да и любого другого) правила невозможно.



    P.S.: Какой из C-компиляторов прав не знаю, нужно действительно в спецификации смотреть. Может в Comeau не ANSI C a например ISO?
     
  14. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    гм...

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

    (int**) => (int*) const* => (const int)* const*



    но в таком случае, учитывая также очевидное правило T* -> T*, получается

    (int**) => (int*)* => (const int)* *



    Или я туплю ?
     
  15. R_NEW

    R_NEW New Member

    Публикаций:
    0
    Регистрация:
    6 май 2005
    Сообщения:
    86
    Адрес:
    Россия
    green



    Напиши так:
    Код (Text):
    1.  
    2.  int **ppi;
    3.  const int **ppci;
    4.  ppci = (const int **)ppi;
    5.  
     
  16. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    R_NEW



    не, const мне не враг

    :derisive:



    если использовать C-подобные приведение типов, то предохраняющие ф-ци const сводятся на нет.



    практически это не представляет проблемы, мне просто хотелось понять логику компилятора.
     
  17. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    green





    Если я правильно понимаю, компилятор проходит цепочку только один раз сверху вниз. На первом шаге получает (int*)* и (const int*)* и смотрит, можно ли с помошью правил T*->const T*, T*->void* и т.д. их приравнять. Если нет, то вылетает с ошибкой, а не проверяет рекурсивно дальше. Поэтому например



    void** v;

    int** i;

    v=i;



    тоже дает ошибку, хотя казалось бы int** => (int*)* => (void*)* => void**





    не надо меня пожалуйста на Вы обзывать :)
     
  18. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    нда...

    ладно, может так и есть, но если решение о допустимости преобразования принимается после dereferencing 1-го уровня тогда таких "правил" немало должно быть...



    Типа умом компилер не понять :)



    Спасибо.





    договорились :)



    PS

    кстати никто не знает как по-русски будет dereference pointer ? Lingvo говорит "разыменовывать", но похоже это не то
     
  19. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    Вот здесь еще один вариант ответа:



    http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17

    Правда если его принять, то остается непонятным, почему int** не приводится к void**. Так что моя версия мне нравится больше :)
     
  20. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Stiver

    Спасибо!