Во время погружения в динамическую память мне пришло в голову, что кажется противоречивым, как тривиальные типы начинают свою жизнь. Рассмотрим фрагмент
void* p = ::operator new(sizeof(int)); // 1
// 2
new (p) int; // 3
Когда int
начать свою жизнь?
Только приобретает хранилище, ::operator new
указано, чтобы иметь эффект (от [New.delete.single])
Функции выделения, вызываемые новым выражением для выделения размера байтов памяти. […] выделяет хранилище, соответствующим образом выровненное для представления любого объекта такого размера, при условии, что тип объекта не имеет нового расширенного выравнивания.
Учитывая, что приобретает хранилище недостаточно при создании объекта int
не может начать свою жизнь здесь.
На данный момент, хранилище подходит для int
был приобретен.
int
создается путем размещения нового. Но как-то здесь его жизнь началась не с [Basic.life]
[…] Говорят, что объект имеет незаполненную инициализацию, если он принадлежит к классу или агрегатному типу, и он или один из его подобъектов инициализируются конструктором, отличным от тривиального конструктора по умолчанию. Время жизни объекта типаT
начинается, когда:
хранение с правильным выравниванием и размером для типа
T
получается, иесли объект имеет непустую инициализацию, его инициализация завершена […]
int
не является ни классом, ни агрегатным типом, следовательно, он имеет пустую инициализацию. Поэтому применяется только первая пуля. Тем не менее, это явно не при получении хранилища и, следовательно, не может быть, когда начинается его срок службы.
Распределители являются обязательными вернуть память без конструирования ее элементов. Но это не имеет смысла для тривиальных типов. Эффекты a.allocate(n)
с a
объект распределителя для типа T
является
Память выделена для
n
объекты типаT
но объекты не построены.
Технически, новое выражение всегда получает хранение. Код 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.
Примечания: Преднамеренно не выполняет никаких других действий.
Хотя «никаких других действий» не выполняется, и, вероятно, реализация оптимизирует любой фактический вызов функции, этот вызов функции распределения все еще считается получением хранилища для объекта, создаваемого объектом. новое выражение.
Других решений пока нет …