Преобразования квалификации C — постоянство

#c

#c

Вопрос:

Может кто-нибудь объяснить, почему второе преобразование разрешено, а первое — нет? Они оба потенциально позволяют изменять постоянное значение lvalue…

 double *wPtr;
const double ** wRef = amp;wPtr;
const double * const * wRef = amp;wPtr;
  

Спасибо,
регулярное

Добавлена ошибка компиляции из Comeau…

 int main( int argc, const char* argv[] )
{
    double *wPtr;
    const double ** wRef = amp;wPtr;
    return 0;
}

Compiling Comeau C/C   4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C   C  0x_extensions

"ComeauTest.c", line 4: error: a value of type "double **" cannot be used to
      initialize an entity of type "const double **"
  const double ** wRef = amp;wPtr;
                         ^

1 error detected in the compilation of "ComeauTest.c".
  

Комментарии:

1. Не могли бы вы опубликовать пример сообщения об ошибке, которое вы получаете при компиляции этого кода? Я думаю, что может происходить что-то еще…

2. @antonm: Нет, он прав в том, что первое представляет собой явную ошибку, обнаруженную компилятором, а второе — нет. Он просто не совсем правильно понимает значение второго.

3. @Nicholas: да, теперь я это понимаю. Кто-то (вы?) был опубликован ответ, который я больше не вижу. В нем была эта полезная ссылка: parashift.com/c -faq-lite/const-correctness.html#faq-18.17

4. @antonm: Я удалил это, когда исправлял. Я только что проснулся и перепутал объяснение. 🙂 Теперь это вернулось.

5. Эта ссылка больше не работает, так что вот она снова: isocpp.org/wiki/faq/const-correctness#constptrptr-conversion

Ответ №1:

Потому что второй пример не допускает модификацию const lvalue (по крайней мере, не без реальных усилий с вашей стороны (приведение, которое само по себе часто является признаком опасности)). Я не уверен, почему вы думаете, что это так, поскольку вы не предоставляете дополнительных объяснений..

 const double * const * wRef = amp;wPtr;
  

Вы должны прочитать это очень внимательно. В нем говорится: «wRef — это указатель на постоянный указатель на double, который является const».

Вы можете изменить wRef (чтобы указывать на другой объект). Вы не можете изменить значение, на которое оно указывает (указатель wPtr), и вы не можете изменить значение, на которое указывает wPtr. Это не предоставляет (обычного) способа изменения значения const lvalue .

Первый пример, конечно, явно опасен и запрещен, как вы и ожидаете.

Кстати, вам следует прочитать главу о корректности C в C FAQ, если вы еще этого не сделали. Раздел 17 рассматривает этот конкретный случай, хотя в основном с точки зрения того, почему первое не разрешено, и явно не пытается описать, почему разрешено второе.

Комментарии:

1. Спасибо, ваш ответ и ссылка на часто задаваемые вопросы по c прояснили ситуацию. Я смотрел на проблему под неправильным углом.

Ответ №2:

Таким образом, наличие слова ‘const’ слева от слова довольно вводит в заблуждение.

Ваше второе утверждение было бы лучше сформулировано как double const * *wRef = amp;wPtr
По сути, это указатель на указатель на const double . Здесь вы можете изменить значение lvalue, потому что оно не является const — const является только значение double, на которое указывается.

Второй является double const * const * wRef — т.е. указатель на константу указывает на константу double.
Сам указатель на указатель может быть изменен, но значение double, на которое он затем указывает, должно быть const . Вы не можете изменить их значение const lvalue.