0

I write code that deals heavily with numbers. For a project I need to pass big "matrices" via MPI between different processes. These matrices are just rectangular number containers I only need to do trivial operations on them. As far as I know to pass such objects in MPI the procedure is to pass a pointer to the first element of the matrix and its size, therefore the matrix must be densely packed, exactly as a plain C array would be:double matrix[n][m], where all the elements are contiguous and immediately after the first row the second row starts. The C++ solution would be to use std::array<std::array<double,m>,n> (n and m are known at compile time) however I have too many data and I need to allocate memory on the heap; I do not think it is possible to allocate std::array on the heap. A similar solution using std::vector would not work since they are not densely packed. Is there a modern C++ solution to the problem? Do I have to use the old C arrays or do I need to write a wrapper class around them? What about using std::valarray<std::valarray<double>> is it guaranteed to be densely packed?

  • Why _not_ use a C-style array? Do you need any of the C++ features? Special iterators? Resizing of arrays? If not, the easiest and most efficient thing is a plain old array. – Dave M. Apr 23 '20 at 06:32
  • Mostly safety, like using the possibility of using .at(). And a bit because of syntactic sugar like the possibility of not defining an operator /= since std::valarray has it defined by itself. I need to perform element wise mathematical operation, I do not need to perform "linear algebra" operations. – alessio lapolla Apr 23 '20 at 06:41
  • "std::vector would not work since they are not densely packed" what exactly do you mean? `std::vector` and `std::array` store their data in a c-array – 463035818_is_not_a_number Apr 23 '20 at 06:53
  • std::vector> is not densely packed. Each row is stored in a contiguous way, but after one row there is the buffer to allow it to grow. – alessio lapolla Apr 23 '20 at 06:56
  • ok then I understood you correctly ;) – 463035818_is_not_a_number Apr 23 '20 at 07:03
  • btw its not the case there is a buffer after each row, but rather the rows can be scattered around in memory. When a vector grows it may need to reallocate and move its elements to different memory – 463035818_is_not_a_number Apr 23 '20 at 07:07
  • 1
    a C++ friendly option is to use `boost::multi_array` as described in an answer at https://stackoverflow.com/questions/21943621/how-to-create-a-contiguous-2d-array-in-c – Gilles Gouaillardet Apr 23 '20 at 07:08

1 Answers1

0

You are right, that

std::vector<std::vector<T>>

is not the best container when it comes to memory locality. The big plus of std::vector is that it used contiguous memory, but a vector of vectors looses that feature. You could consider to use a

std::vector<std::array<T>>

which is probably the most cache-friendly nested 2D array. Everything is in contiguous memory, only what std::array stores in addition to the actual data comes in between. To get real contiguous memory for a 2D data structure on the heap you should use a plain

std::vector<T>

with width * height elements. 2D access can be emulated by tranforming the index ( (i,j) -> i) and std::vector<T>::data() gets you a pointer to the underlying c-array that has nothing but your elements in contiguous memory.

463035818_is_not_a_number
  • 88,680
  • 9
  • 76
  • 150