Неявное создание объектов в C ++ 20, понимание примера типа предложения предложения - PullRequest
3 голосов
/ 26 апреля 2020

Я пытаюсь полностью понять новую функцию C ++ 20, неявное создание объектов.

Этот пример содержится в предложении , раздел «3.3 Тип штамповки»:

Мы не будем sh примеров, таких как следующие, чтобы стать valid:

float do_bad_things(int n) {
    alignof(int) alignof(float) char buffer[max(sizeof(int), sizeof(float))];
    *(int*)buffer = n;                      // #1
    new (buffer) std::byte[sizeof(buffer)]; // #X
    return (*float*)buffer;                 // #2
}

Предложенное правило позволит объекту int возникать, чтобы сделать строку # 1 действительной (в каждом случае), и позволит объекту с плавающей точкой также возникать, чтобы создать строку # 2 действителен.

Почему необходима строка, помеченная #X (мной)? Есть ли разница? Разве пример не был бы точно таким же, если бы этой строки не было?

Я рассуждаю так: buffer это массив символов, поэтому он неявно создает объекты. Итак, в строке # 1 неявно создается int. Аналогично, в строке № 2 float создается неявно, даже без строки #X (поскольку buffer уже имеет свойство implicitly create-objects). Так что, похоже, строка #X ничего не добавляет. Я не прав?

1 Ответ

4 голосов
/ 26 апреля 2020

Почему необходима строка с пометкой #X (мной)?

Поскольку это вызывает неявное создание объекта.

Неявное создание объекта (IO C) в C ++ 20 не хаос . Это не «каждый объект существует во всех возможных местах памяти в любое время». Вместо этого это своего рода квантовое состояние: когда правила IO C вызываются над частью памяти, создается один объект. Вы просто не знаете, что это такое. Когда вы фактически используете память для определенного объекта, оказывается, что это тот объект (или тот, который совместим с ним), который был создан в момент вызова IO C в памяти.

И если вы делаете что-либо с хранилищем так, что один объект не может удовлетворить оба, и тогда вы получаете UB.

Кусок памяти не может одновременно хранить int и float в пределах их времен жизни. IO C не меняет этого.

В строке 1 IO C используется для создания int в хранилище; в этот момент он функционально не отличается от int buffer;. Строка 2 пытается получить доступ к float в этом хранилище, но такого объекта не существует. Если int уже есть, IO C не может создать float поверх него.

Строка X завершает время жизни всех объектов в этой памяти, повторно используя хранилище; int там больше нет. И поскольку создаваемый объект является массивом byte, это также освобождает хранилище для ввода-вывода C. Это то, что заставляет линию 2 работать.

...