В какой момент запускается время жизни тривиального типа, созданного путем размещения-нового?

Во время погружения в динамическую память мне пришло в голову, что кажется противоречивым, как тривиальные типы начинают свою жизнь. Рассмотрим фрагмент

void* p = ::operator new(sizeof(int));  // 1
// 2
new (p) int; // 3

Когда int начать свою жизнь?

  1. Только приобретает хранилище, ::operator new указано, чтобы иметь эффект (от [New.delete.single])

    Функции выделения, вызываемые новым выражением для выделения размера байтов памяти. […] выделяет хранилище, соответствующим образом выровненное для представления любого объекта такого размера, при условии, что тип объекта не имеет нового расширенного выравнивания.

    Учитывая, что приобретает хранилище недостаточно при создании объекта int не может начать свою жизнь здесь.

  2. На данный момент, хранилище подходит для int был приобретен.

  3. int создается путем размещения нового. Но как-то здесь его жизнь началась не с [Basic.life]

    […] Говорят, что объект имеет незаполненную инициализацию, если он принадлежит к классу или агрегатному типу, и он или один из его подобъектов инициализируются конструктором, отличным от тривиального конструктора по умолчанию. Время жизни объекта типа T начинается, когда:

    • хранение с правильным выравниванием и размером для типа T получается, и

    • если объект имеет непустую инициализацию, его инициализация завершена […]

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

Некоторый контекст

Распределители являются обязательными вернуть память без конструирования ее элементов. Но это не имеет смысла для тривиальных типов. Эффекты a.allocate(n) с a объект распределителя для типа T является

Память выделена для n объекты типа T но объекты не построены.

6

Решение

Технически, новое выражение всегда получает хранение. Код new(p) int и получает хранилище, и создает объект, и в соответствии с [basic.life] / 1 время жизни объекта начинается, когда new(p) int получил хранение.

Согласно N4659 [expr.new], код new(p) int генерирует вызов функции распределения ::operator new(sizeof(int), p), А в [new.delete.placement] стандартная библиотека определяет такую ​​функцию:

void* operator new(std::size_t size, void* ptr) noexcept;

Возвращает: PTR.

Примечания: Преднамеренно не выполняет никаких других действий.

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

7

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]