Квалификаторы const
для членов позволяют компилятору предполагать, что - после инициализации объекта - эти члены не должны быть изменены каким-либо образом, и он может соответствующим образом оптимизировать код (см., Например, комментарий @Ajay Brahmakshatriya ).
Таким образом, важно отличать фазу инициализация от последующих фаз, где будут применяться назначения , т.е. с какого момента компилятор может предположить, что объект был инициализирован и имеет действующий тип, на который можно положиться.
Я думаю, что есть главное различие между вашим примером и тем, что в принятом ответе вы привели. В ответе this SO целевой агрегатный объект с константными типами элементов создается с помощью malloc
:
ImmutablePoint init = { .x = x, .y = y };
ImmutablePoint *p = malloc(sizeof *p);
memcpy(p, &init, sizeof *p);
В соответствии с правилами доступа к сохраненному значению объекта (см. Эту часть онлайнового стандартного черновика c ), целевой объект p
получит свой эффективный тип впервые в ходе исполнения memcpy
; эффективный тип - это тип исходного объекта init
, а первый memcpy
объекта, получившего malloced
, можно рассматривать как инициализацию. Однако впоследствии изменение константных членов целевого объекта будет UB (я думаю, что даже секунда memcpy
будет UB, но это, вероятно, основано на мнении).
6,5 выражений
- Эффективным типом объекта для доступа к его сохраненному значению является объявленный тип объекта, если таковой имеется.87) ... Если значение равно
скопировать в объект, не имеющий объявленного типа, используя memcpy или memmove,
или копируется как массив символьного типа, тогда эффективный тип
измененный объект для этого доступа и для последующих обращений, которые
не изменять значение - это эффективный тип объекта, из которого
значение копируется , если оно есть. Для всех других доступов к
объект не имеет объявленного типа, эффективный тип объекта
просто тип lvalue, используемый для доступа.
87) Выделенные объекты не имеют объявленного типа.
Однако в вашем примере целевой объект dst
уже имеет объявленный тип в своем определении struct vector dst;
. Следовательно, квалификаторы const на элементах dst
уже существуют до применения memcpy
, и его следует рассматривать как назначение, а не как инициализацию.
Так что я бы проголосовал за UB в этом случае.