Как конвертировать между плоскими и многомерными массивами без копирования данных? - PullRequest
1 голос
/ 19 июня 2019

У меня есть некоторые данные, структурированные как многомерный массив, т.е. double[][], и мне нужно передать их функции, которая ожидает один линейный массив double[] вместе с многомерными метаданными для многомерногопредставление.

Например, у меня может быть многомерный массив 3 x 5, который мне нужно передать как 15-элементный плоский массив вместе с параметрами высоты и ширины, чтобы функция знала, что это массив 3x5, а нечем массив 5x3.

Затем функция вернет метаданные плоского массива и размера, которые мне нужно использовать для преобразования данных обратно в многомерный тип.

Я считаю, что расположение данных впамять одинакова как для плоских, так и для многомерных представлений;единственное отличие состоит в том, как выполняются операции индексации.Поэтому я хотел бы выполнить «преобразование» с типизацией типов, а не копировать значения массива.

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

Я действительно знаю, каковы будут размеры многомерного массива во время компиляции.Размеры массива не являются динамическими.

Ответы [ 4 ]

2 голосов
/ 19 июня 2019

Самый правильный способ дал @Maxim Egorushkin и @ypnos: double *flat = &multi[0][0];.И это будет хорошо работать с любым приличным компилятором.Но, к сожалению, недопустимый код C ++ и вызывает неопределенное поведение.

Проблема в том, что для массива double multi[N][M]; (N и M являются выражениями, связанными со временем компиляции), &multi[0][0] является адресомпервый элемент массива размером M.Так что арифметика указателей допустима только до M.Смотрите этот мой вопрос для более подробной информации.

1 голос
/ 19 июня 2019

Какой самый правильный и читаемый способ типизации между многомерными и плоскими массивами одинакового общего размера?

Адрес первого элемента массива совпадает с адресом массива. Вы можете передать адрес первого элемента, приведение не требуется.

1 голос
/ 19 июня 2019

Я бы предположил, что самый популярный способ сделать это:

double *flat = &multi[0][0];

Вот как это делается в C, и вы работаете с простыми массивами C.

Вы также можете взглянуть на std::array в вашем случае использования (измерения известны во время компиляции), но он не является многомерным, поэтому, если вы его каскадируете, вы потеряете смежный макет.

0 голосов
/ 19 июня 2019

Вы можете использовать приведение к ссылке на массив.Для этого требуется использовать какой-то причудливый синтаксис типа C ++, но взамен он позволяет использовать все функции, которые работают с массивами, например для каждого цикла.

#include <iostream>

using namespace std;

int main()
{
    static constexpr size_t x = 5, y = 3;
    unsigned multiArray[x][y];
    for (size_t i = 0; i != x; ++i)
        for (size_t j = 0; j != y; ++j)
            multiArray[i][j] = i * j;

    static constexpr size_t z = x * y;
    unsigned (&singleArray)[z] = (unsigned (&)[z])multiArray[0][0];
    for (const unsigned value : singleArray)
        cout << value << ' ';
    cout << endl;

    return 0;
}

Учтите, что этот и другие методы, основанные на приведениях, работают толькос реальными многомерными массивами.Если это массив массивов (например, unsigned **multiArray;), он не размещается в непрерывном блоке памяти, и приведение не может обойти это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...