Является ли перемещение объекта в память malloc действительным C ++? - PullRequest
0 голосов
/ 09 февраля 2019

Если память выделяется с помощью malloc (в отличие от new) и объект перемещается в эту память, это допустимый C ++?Допустим, я выделил память для массива из n объектов типа T, и у меня есть диапазон из n объектов типа T, в который я хочу перейти, это действительно:

T* next = (T *)malloc(n*sizeof(T));
T* t = std::begin(my_range);
while (we still have more Ts) {
  *next = std::move(*t);   
  ++next;
  ++t;
}

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

Я предполагаю, что Размещение нового является правильным способом сделать это:

while (we still have more Ts) {
  new (next) T(*t);
  ++next;
  ++t;
}

, но я хотел бы знать, ПОЧЕМУ первое неверно, и еслитак что, если это просто работает по счастливой случайности или потому что T оказывается POD.

1 Ответ

0 голосов
/ 09 февраля 2019

Если память выделена с помощью malloc (в отличие от new) и объект перемещен в эту память, является ли это допустимым C ++?

Потенциально;Не обязательно.

Если мы рассмотрим перемещение-конструкцию, то, конечно, вы можете использовать размещение-новый, чтобы создать объект в памяти.Немного похоже на ваш второй пример - за исключением того, что пример делает копию;если итератор не является странным и не возвращает значение.Хотя вы упоминаете, что тип является POD, в этом случае нет разницы между перемещением и копией.

Если мы рассмотрим назначение перемещения, то оно будет четко определено, только если ранее был создан объект вэта память.В вашем первом примере объекты не были созданы, поэтому поведение технически не определено.

Я хотел бы знать [...], работает ли он просто по счастливой случайности или потому, что T оказываетсястручок

Технически UB, но, скорее всего, будет работать, если T - POD.Этот тип инициализации по присваиванию хорошо определен в C (и это единственный способ динамического создания объектов на этом языке).

Если бы оператор присваивания был нетривиальным, то вещи, скорее всего, сломались бы.


Чтобы переместить ряд объектов в неинициализированную память, вы, вероятно, захотите использовать std::uninitialized_move.Он будет хорошо определен независимо от тривиальности типа, и вам даже не нужно писать цикл.

...