Безопасно ли получить доступ к неконстантному объекту через const lvalue?

2
задан StoryTeller 19 March 2019 в 08:49
поделиться

2 ответа

Теперь рассмотрим следующий код:

void print_double(const double d){
    printf("d = %lf\n", d);
}

int main(int args, const char *argv[]){
    double d = 10.2;
    print_double(d);
}

Ваш код не имеет псевдонимов. d в main и d в print_double являются различными объектами, поскольку аргументы всегда передаются по значению. Но если бы мы «исправили» пример:

void print_double(const double *pd){
    printf("d = %lf\n", *pd);
}

int main(int args, const char *argv[]){
    double d = 10.2;
    print_double(&d);
}

Это все еще хорошо определено. *pd является lvalue типа const double. const double является квалифицированной версией double. Все типы совместимы между собой (тривиально). Таким образом, вторая пуля имеет место, и этот псевдоним действителен.

0
ответ дан StoryTeller 19 March 2019 в 08:49
поделиться

Если два указателя (lvalue доступы) могут , псевдоним - это другое дело, чем если бы они указывали на совместимых типов . Часть, которую вы цитируете, посвящена псевдониму указателя (так называемое «правило строгого псевдонима»), который по какой-то причине записывается как:

  • тип, совместимый с эффективным типом объекта, [1116 ]
  • квалифицированная версия типа, совместимого с эффективным типом объекта

Что означает, что объект с квалификацией const может псевдоним не Квалифицированный объект, даже если они не являются совместимыми типами. Пример:

void f (const int* a, int* b);

a могут указывать на те же данные, что и b. Компилятор не вправе предполагать, что они указывают на отдельные объекты.

Но это даже не относится к вашему случаю, так как вы передаете параметр по значению и создаете локальную копию. Псевдоним будет применяться, если ваш пример был таким:

double a = 10.2;

int main(int args, const char *argv[]){
    print_double(&a);
}

void print_double(const double* b){
    printf("d = %lf\n", b);
}

Где параметр b - это квалифицированная версия типа, совместимого с эффективным типом объекта (double). Поэтому компилятор может не предполагать, что b не указывает на глобальную переменную a.


Относительно совместимости:

Всякий раз, когда вы копируете объект либо с помощью присваивания =, либо путем передачи его в качестве параметра функции, правила простого присвоения включаются. 6.5.16.1 позволяет это:

  • левый операнд имеет атомарный, квалифицированный или неквалифицированный тип указателя, и (учитывая тип, который левый операнд будет иметь после преобразования в lvalue) оба операнда являются указателями на квалифицированные или неквалифицированные версии совместимых типов, а тип, на который указывает левый, имеет все квалификаторы типа, на который указывает правый;

Значение int* a; const int* b = a; в порядке, но const int* a; int* b = a; является нарушением ограничения , Те же самые правила применяются во время передачи параметров, см. 6.9.1 / 10:

При входе в функцию оцениваются выражения размера каждого изменяемого параметра, а значение каждого выражения аргумента преобразуется. к типу соответствующего параметра как по присваиванию.

В вашем случае происходит то, что значение d в вызывающей стороне копируется в новую переменную типа const double. Это разрешено согласно правилу простого присваивания, и вы создаете новую переменную - все хорошо.

0
ответ дан Lundin 19 March 2019 в 08:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: