C ++ выделяет N-мерный вектор без копирования c-массива - PullRequest
0 голосов
/ 28 августа 2018

Я хочу загрузить N-мерные матрицы с диска (HDF5) в std::vector объекты.

Я заранее знаю их ранг, но не форму. Например, одна из матриц имеет 4 ранга std::vector<std::vector<std::vector<std::vector<float>>>> data;

Я хочу использовать векторы для хранения значений, потому что они стандартные и не такие уродливые, как c-массивы (в основном потому, что они знают о своей длине).

Однако способ их загрузки заключается в использовании функции загрузки, которая принимает void *, что прекрасно работает для векторов ранга 1, где я могу просто изменить их размер и затем получить доступ к его указателю данных (vector.data()). Для более высоких рангов vector.data() будет просто указывать на vector с, а не на фактические данные.

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

Есть ли способ иметь непрерывные многомерные данные в векторах и затем получить к ним один адрес?

Ответы [ 3 ]

0 голосов
/ 28 августа 2018

Для двумерной матрицы вы можете использовать такой уродливый c-массив:

float data[w * h]; //width, height
data[(y * w) + x] = 0; //access (x,y) element

Для трехмерной матрицы:

float data[w * h * d]; //width, height, depth
data[((z * h) + y) * w + x] = 0; //access (x,y,z) element

И так далее. Чтобы загрузить данные, скажем, из файла,

float *data = yourProcToLoadData(); //works for any dimension

Это не очень масштабируемо, но вы имеете дело с известным измерением. Таким образом, ваши данные будут непрерывными, и у вас будет один адрес.

0 голосов
/ 28 августа 2018

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

Вместо вашего плана загрузите в вектор flst.

Затем оберните его многомерным видом.

template<class T, size_t Dim>
struct dimensional{
  size_t const* strides;
  T* data;
  dimensional<T, Dim-1> operator[](size_t i)const{
     return {strides+1, data+i* *strides};
  }
};
template<class T>
struct dimensional<T,0>{
  size_t const* strides; // not valid to dereference
  T* data;
  T& operator[](size_t i)const{
     return data[i];
  }
};

где strides указывает на массив шагов массива для каждого измерения (произведение размеров всех последующих измерений).

То есть my_data.access()[3][5][2] получает определенный элемент.

Этот эскиз решения оставляет все открытым и не поддерживает итерацию for(:). Более высокое качество доставки будет иметь надлежащую конфиденциальность и поддержку стиля для циклов.

Мне неизвестно название уже написанного для вас высококачественного многомерного массива, но почти наверняка оно есть.

0 голосов
/ 28 августа 2018

Если вы беспокоитесь о производительности, пожалуйста, не используйте вектор vector of vector ....

Здесь вот почему. Я думаю, что ответ @ OldPeculier стоит прочитать.

Причина, по которой он толстый и медленный, на самом деле одна и та же. Каждая «строка» в матрице представляет собой отдельно выделенный динамический массив. Распределение кучи требует больших затрат как во времени, так и в пространстве. Распределитель требует времени, чтобы выполнить выделение, иногда запуская O (n) алгоритмы, чтобы сделать это. И распределитель «дополняет» каждый из ваших массивов строк дополнительными байтами для учета и выравнивания. Это дополнительное место стоит ... ну ... дополнительное место. Для освобождения матрицы также потребуется дополнительное время для освобождения матрицы, кропотливого освобождения каждого отдельного выделения строки. Встает в меня, просто думая об этом.

Есть еще одна причина, по которой он медленный. Эти отдельные распределения имеют тенденцию жить в прерывистых частях памяти. Одна строка может быть по адресу 1000, другая по адресу 100000 - вы поняли. Это означает, что когда вы пересекаете матрицу, вы перепрыгиваете через память, как дикий человек. Это приводит к потере кеша, что значительно замедляет время обработки.

Итак, если у вас есть абсолютный синтаксис индексации [x] [y], используйте это решение. Если вы хотите быстроты и малости (и если вас это не волнует, почему вы работаете в C ++?), Вам нужно другое решение.

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