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?

apelle
  • 144
  • 1
  • 9
  • 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. – apelle 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_an_ai 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. – apelle Apr 23 '20 at 06:56
  • ok then I understood you correctly ;) – 463035818_is_not_an_ai 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_an_ai 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

1

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. Alternatively consider

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_an_ai
  • 109,796
  • 11
  • 89
  • 185