Обычная идиома при построении буферов (скажем, кольцевого буфера) для объектов типа класса T состоит в инициализации объекта T * с адресом памяти, полученным из std :: mallo c () или оператора new (), и затем для создания объектов в этом буфере по требованию, используя размещение new, используя арифметику указателя c на указатель T для обхода блока памяти.
Хотя весьма маловероятно, что существует какой-либо компилятор, для которого это не будет работать (это работает с g ++ и clang ++), мне кажется, строго говоря, это может иметь неопределенное поведение. Это связано с тем, что §8.7 / 4 C ++ 17, по-видимому, разрешает арифметику указателей c только для массивов, а блок памяти, возвращаемый mallo c, оператором new или оператором new [], не является массивом, поскольку я Я понимаю, что только новое выражение [] может создать массив в динамической памяти c, который, таким образом, будет полностью инициализирован в точке построения.
Это также заставило меня задуматься о том, что эталонная реализация std :: uninitialized_copy имеет неопределенное поведение для динамически выделяемой неинициализированной памяти, потому что его эталонная реализация в §23.10.10.4 / 1 C ++ 17 использует арифметику указателя c на итераторе назначения, который здесь будет указателем.
Возможно, то же самое относится к std :: uninitialized_copy, если неинициализированная память получается нединамически, скажем, с использованием выровненного массива без знака char или std :: byte, как это разрешено в §4.5 / 3 C ++ 17, потому что arithmeti c в §8.7 / 4 подразумевает, что тип указателя назначения, по которому арифметика c должен выполняться тип элемента массива (unsigned char или std :: byte), а не тип, созданный в нем с использованием размещения new.
Это кажется удивительным. Кто-нибудь может указать на недостаток (если таковой имеется) в этом рассуждении.