Хорошо ли он определен для ссылки на переменную до ее создания? - PullRequest
6 голосов
/ 15 апреля 2020

По духу это похоже на вопрос , который был задан и отвечен на c. Комментарии там подразумевают, что точный ответ будет отличаться для c++, поэтому вот аналогичный вопрос для кода, написанного в c++.

Хорошо ли определена следующая программа?

int f(int& b) 
{ 
  b = 42; 
  return b; 
}

int a { f(a) };

Мне кажется, все в порядке, но, с другой стороны, как a создается из значения, которое вычисляется функцией, которая сама изменяет a? У меня чувство курицы и яйца по этому поводу, поэтому объяснение было бы неплохо. Что бы это ни стоило, кажется работающим.

Кажется, это тот же самый вопрос, так что здесь идет; будет ли ответ отличаться для типов классов и основных типов. т. е. хорошо ли сформировано следующее?

struct S { int i; };

S f(S& b) 
{ 
    b.i = 42; 
    return b; 
}

S a { f(a) };

Опять же, для чего стоит, этот , кажется, также работает.

1 Ответ

6 голосов
/ 15 апреля 2020

Поведение кажется неопределенным в C ++ 20. Изменение было сделано P1358 , разрешающим CWG 2256. Поскольку разрешения дефектов, как правило, имеют обратную силу, этот код следует рассматривать как UB во всех версиях C ++.

Согласно [basi c .life] / 1 :

... Время жизни объекта типа T начинается, когда:

  • хранилище с правильным выравниванием и размер для типа T получается, и
  • его инициализация (если есть) завершена (включая пустую инициализацию) ...

В то время, когда f(a) вызвано, объект a еще не начал свое время жизни, так как его инициализация не завершена. Согласно [basi c .life] / 7 :

Аналогично, до начала срока службы объекта, но после того, как было выделено хранилище, которое будет занимать объект ... может использоваться любое значение, относящееся к исходному объекту, но только ограниченным образом. ... Программа имеет неопределенное поведение, если:

  • glvalue используется для доступа к объекту ...

Таким образом, запись в a перед его инициализация завершена - UB, даже если хранилище уже выделено.

...