C ++ 17: является ли модифицируемый временный объект (и хранилище), созданный компилятором для (статической длительности хранилища) привязки константной ссылки? - PullRequest
0 голосов
/ 29 января 2019

Позволяет скомпилировать следующее объявление верхнего уровня

const int& ri = 5;

с помощью clang++-std=c++14 и ниже он помещает временный объект (и указатель, представляющий ссылку) в раздел .rodata:

        .type   _ZGR2ri_,@object        # @_ZGR2ri_
        .section        .rodata,"a",@progbits
        .p2align        2
_ZGR2ri_:
        .long   5                       # 0x5
        .size   _ZGR2ri_, 4

        .type   ri,@object              # @ri
        .globl  ri
        .p2align        3
ri:
        .quad   _ZGR2ri_
        .size   ri, 8

Но если мы изменим стандартную версию на -std=c++17 (или выше)объект будет помещен в секцию .data (хотя указатель по-прежнему находится в .rodata):

        .type   _ZGR2ri_,@object        # @_ZGR2ri_
        .data
        .p2align        2
_ZGR2ri_:
        .long   5                       # 0x5
        .size   _ZGR2ri_, 4

        .type   ri,@object              # @ri
        .section        .rodata,"a",@progbits
        .globl  ri
        .p2align        3
ri:
        .quad   _ZGR2ri_
        .size   ri, 8

В чем причина такого поведения?Это ошибка?Тот факт, что он все еще заменяет все варианты использования ri в том же TU своим начальным значением 5, предполагает, что это ошибка.

Моя гипотеза заключается в том, что в [dcl.init.ref] /5.2

Если преобразованный инициализатор является prvalue, его тип T4 настраивается на тип «cv1 T4» ( [conv.qual] ) и временныйприменяется преобразование материализации.

оно наивно отбрасывает (или, скорее, не добавляет) cv1 -квалификатор из (в) типа prvalue.

Самое смешное, что еслизаменив выражение инициализатора значением prvalue не связанного со ссылками, но конвертируемого типа

const int& ri = 5.0;

, он снова начинает помещать объект со значением 5 в раздел .rodata.

Есть ли в стандарте что-нибудь, что теперь требует такой изменчивости? Другими словами:

  • это объект, обозначенный ri, изменяемый с помощью соответствующего кода?(очевидно, что код, включающий UB, может попытаться изменить его, и компилятор не обязан прилагать усилия для того, чтобы это разрешить)
  • - это хранилище этого объекта, изменяемое с помощью соответствующего кода путем его повторного использования для создания другого объектаразмер не больше размера временного «псевдонима» («ссылки являются псевдонимами») на ri, то есть sizeof (int)?

1 Ответ

0 голосов
/ 30 января 2019

Давайте проанализируем

const int& ri = 5;

Из черновика C ++: инициализация ссылок [dcl.init.ref] / 5

Ссылка на тип«Cv1 T1» инициализируется выражением типа «cv2 T2» следующим образом:

Здесь cv1 = const, T1 = int, cv2 = "", T2 = int

пропуская неприменимые предложения, мы получаем здесь [dcl.init.ref] /5.3:

В противном случае, если выражение инициализатора (5.3.1)является rvalue (но не битовым полем) (...) и «cv1 T1» совместим со ссылками с «cv2 T2», или (...) тогда значение выражения инициализатора(...) называется преобразованным инициализатором.

Преобразованный инициализатор равен 5 a.

Если преобразованный инициализатор равен prvalue , его тип T4 настраивается на тип «cv1 T4».»([Conv.qual]) и применяется временное преобразование материализации ([conv.rval]).В любом случае, ссылка связана с полученным значением glvalue (...)

cv1 T4 = const int

Таким образом, создается объект типа const int иссылка на него обязательна.

"Преобразование временной материализации" - это новая концепция, объясненная здесь [conv.rval] :

Значение типа T может бытьпреобразуется в значение x типа T. Это преобразование инициализирует временный объект ([class.teilitary]) типа T из значения prvalue, оценивая значение prvalue с временным объектом в качестве объекта результата и создает значение xvalue.обозначает временный объект.Тип T должен быть полным.

Итак, у нас есть преобразование prvalue -> xvalue -> lvalue.

Время жизни временного элемента описано в [class.teditional] / 6 :

Временный объект, к которому привязана ссылка, или (...) сохраняется в течение времени жизни ссылки , если glvalue, к которому относится ссылкассылка была получена одним из следующих способов:

(6.1) временное преобразование материализации ([conv.rval]), (...)

Так что этоcase и время жизни временного "сохраняется в течение времени жизни ссылки" .

[basic.life] / 5

Программа может завершить время жизни любого объекта, повторно используя хранилище, занимаемое объектом

, но не каждое хранилище объектов может использоваться таким образом: [basic.memobj] / 10

Создание в хранилище нового объекта, который является постоянным завершенным объектом со static, тhread, или длительность автоматического хранения или внутри хранилища, которое такой const-объект занимал до истечения срока его службы, приводит к неопределенному поведению.

Здесь определяется срок хранения [basic.stc]

Срок хранения - это свойство объекта, которое определяет минимальный потенциальный срок службы хранилища, содержащего объект.Срок хранения определяется конструкцией, используемой для создания объекта, и является одним из следующих: (1.1) длительность статического хранения (1.2) длительность хранения потока (1.3) длительность автоматического хранения (1.4) продолжительность динамического хранения 2 Static,поток и время автоматического хранения связаны с объектами , представленными объявлениями ([basic.def]) и , неявно созданными реализацией .

Но тогда только текступоминает переменные , а не объекты .Я не вижу, где определяется продолжительность хранения временного файла!

РЕДАКТИРОВАТЬ: @LanguageLawyer указывает мне на этот дефект ядра:

1634.Продолжительность временного хранения

Очевидное намерение ссылки на 15,2 [class.teven] состоит в том, чтобы временное хранилище, срок службы которого был увеличен до срока обращения с одним из этих хранилищСчитается также, что длительности ge имеют такую ​​длительность хранения.

(...) спецификация продления времени жизни временных (также в п. 5 пункта 15.2 [class.teven]) ничего не говорит о хранениипродолжительность .Кроме того, ни в одном из этих мест ничего не сказано о сроке хранения временного устройства, срок службы которого не продлен.

Так что в спецификации действительно отсутствует часть;время жизни этих объектов, созданных реализацией, точно не указано.Спецификация времени жизни в C ++ сложна , как вы можете видеть из множества дополнений в спецификации времени жизни, объединений, подобъектов и "вложенных" в более позднем стандарте;некоторые из этих новых положений применимы даже к коду, который не использует новую функцию C ++, коду, который должен был поддерживаться (но недостаточно хорошо описан) в предстандартный период времени ARM, например, коду, который ничего не делал, кроме изменения "«активный член» объединения.

Если спецификация интерпретируется так, как заявлено в DR, является намерением, то время жизни временного const int со значением 5 будет иметь статическую длительность хранения; его память не может быть изменена с юридической точки зрения и может быть помещена в секцию только для чтения .

(Другое решение: комитет также может составить специальный класс хранения для временных .) * * тысяча сто тридцать шесть

...