Я пишу код, который активно работает с числами. Для проекта мне нужно передавать большие «матрицы» через MPI между разными процессами. Эти матрицы представляют собой просто контейнеры с прямоугольными числами. Мне нужно выполнять над ними только тривиальные операции. Насколько я знаю, чтобы передать такие объекты в MPI, нужно передать указатель на первый элемент матрицы и его размер, поэтому матрица должна быть плотно упакована, точно так же, как обычный массив C:double matrix[n][m]
, где все элементы являются смежными, и сразу после первой строки начинается вторая строка. Решение C++ состоит в том, чтобы использовать std::array<std::array<double,m>,n>
(n и m известны во время компиляции), однако у меня слишком много данных, и мне нужно выделить память в куче; Я не думаю, что можно выделить std::array
в куче. Аналогичное решение с использованием std::vector
не сработает, так как они не плотно упакованы. Есть ли современное решение проблемы на С++? Должен ли я использовать старые массивы C или мне нужно написать вокруг них класс-оболочку? А как насчет использования std::valarray<std::valarray<double>>
, гарантированно ли он будет плотно упакован?
Плотно упакованный контейнер С++
- Почему бы не использовать массив в стиле C? Нужны ли вам какие-либо функции C++? Специальные итераторы? Изменение размера массивов? Если нет, то проще всего и эффективнее использовать старый добрый массив. 23.04.2020
- В основном безопасность, например возможность использования .at(). И немного из-за синтаксического сахара, такого как возможность не определять оператор /=, поскольку std::valarray определяет его сам. Мне нужно выполнить поэлементную математическую операцию, мне не нужно выполнять операции линейной алгебры. 23.04.2020
- std::vector не будет работать, так как они не плотно упакованы, что именно вы имеете в виду?
std::vector
иstd::array
хранят свои данные в c-массиве 23.04.2020 - std::vector‹std::vector‹double›› упакован не плотно. Каждая строка хранится непрерывно, но после одной строки есть буфер, позволяющий ей расти. 23.04.2020
- хорошо, значит я вас правильно понял ;) 23.04.2020
- Кстати, дело не в том, что после каждой строки есть буфер, а в том, что строки могут быть разбросаны по памяти. Когда вектор растет, может потребоваться перераспределить и переместить его элементы в другую память. 23.04.2020
- дружественный к С++ вариант - использовать
boost::multi_array
, как описано в ответе в заголовке stackoverflow.com/questions/21943621/ 23.04.2020
Ответы:
Вы правы, что
std::vector<std::vector<T>>
не лучший контейнер, когда дело доходит до локальности памяти. Большим плюсом std::vector
является то, что он использует непрерывную память, но вектор из векторов теряет эту функцию. Вы можете рассмотреть возможность использования
std::vector<std::array<T>>
который, вероятно, является наиболее удобным для кэширования вложенным 2D-массивом. Все находится в непрерывной памяти, только то, что std::array
хранит в дополнение к фактическим данным, находится между ними. Чтобы получить реальную непрерывную память для 2D-структуры данных в куче, вы должны использовать простой
std::vector<T>
с width * height
элементами. 2D-доступ можно эмулировать путем преобразования индекса ( (i,j) -> i
), а std::vector<T>::data()
дает вам указатель на базовый c-массив, который не имеет ничего, кроме ваших элементов в непрерывной памяти.