Скопируйте 2D-массив с помощью memcpy?

Итак, я хочу скопировать содержимое 2D-массива в другой массив того же типа. Вот как создается массив:

 GridUnit** newGrid;
 newGrid = new GridUnit*[width];
    for (int i = 0; i < width; i++)
        newGrid[i] = new GridUnit[height];

GridUnit - это размер 16 (4 поплавка). Так что все инициализированные штрафы, никаких проблем с его использованием, как и после того, как я запустил циклы for, чтобы фактически заполнить значения некоторыми данными. Теперь то, что я хочу сделать, это скопировать содержимое другого массива в этот (без петель, если это возможно). Это то, что я пытался сделать до сих пор:

 memcpy(&newGrid, &grid, height * width * 16);

'grid' идентичен "newGrid" по размеру и типу. Однако это не работает. Я знаю, что memcpy, возможно, неверен, но, используя это, я попытался использовать несколько разных настроек, я не знаю, что с ним не так, поэтому любая помощь будет приветствоваться!

Ответ 1

Если у вас действительно есть двумерный массив, этот вызов memcpy будет работать. Но вы этого не сделаете, у вас есть width отдельных несмежных 1-D массивы, собранные в массиве указателей.

Можно динамически выделять непрерывный блок, в котором количество строк и столбцов изменяется во время выполнения и сохраняет двухскриптовый доступ. Вам придется изменить код распределения следующим образом:

GridUnit** newGrid;
newGrid = new GridUnit*[width];
newGrid[0] = new GridUnit[width * height];
for (int i = 1; i < width; i++)
    newGrid[i] = newGrid[i-1] + height;

Распределение становится проще:

delete[] newGrid[0];
delete[] newGrid;

Там нет delete[] для newGrid[i] с i > 0 потому что у них нет своих собственных блоков, они просто указывают на один большой блок. Поскольку все смежно, вы можете думать о newGrid[0] либо как указатель на первую строку (элементы height), либо как весь двумерный массив (элементы width * height).

И тогда вы можете получить доступ ко всем данным в виде единого непрерывного блока:

memcpy(newGrid[0], oldGrid[0], height * width * sizeof newGrid[0][0]);

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

std::unique_ptr<GridUnit[]> newData;
std::unique_ptr<GridUnit*[]> newGrid;
newData.reset(new GridUnit[width * height]);
// or newData = std::make_unique<GridUnit[]>(width * height);
newGrid.reset(new GridUnit*[width]);
// or newGrid = std::make_unique<GridUnit*[]>(width);
for (int i = 0; i < width; i++)
    newGrid[i] = &newData[i * height];