0

Suppose I require an undetermined number of 3-by-4 matrices. (Or a sequence of any other fixed m-by-n-dimensional matrices.) My first thought is to store these matrices in a std::vector, where each matrix is itself a std::vector<std::vector<double> >. How can I use std::vector::reserve() to preallocate space for a number, say x, of these matrices? Because I know two of the dimensions, I ought (or I'd like) to be able to x times the size of these blocks.

I know how to implement this object in a 1D std::vector, but I'd like to know how to do it in a 3D std::vector, if for no other reason than to better learn how to use the std::vector class.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
synaptik
  • 8,971
  • 16
  • 71
  • 98

2 Answers2

1

Storing matrices as vectors-of-vectors is probably pretty inefficient, but if you must, go for it. Reserving space is the same as always:

typedef std::vector<std::vector<int>> matrix_type;

std::vector<matrix_type> collection;

collection.reserve(100);  // set capacity for 100 "matrices"

// make 10 4x3-matrices; `collection` won't reallocate
collection.resize(10, matrix_type(4, std::vector<int>(3)));

For your base type you might be better of to have a single vector of m * n elements and access it in strides, i.e. the (i,j)th element would be at position i * n + j. Each vector itself is a dynamic container, and you probably don't want all that many dynamic allocations all over the place.

In the same vein, the above reserve call probably doesn't do what you think, as it only reserves memory for the inner vector's bookkeeping data (typically three words per vector, i.e. 300 words), and not for the actual data.

In that light, you might even like to consider an std::array<int, m*n> as your matrix type (and access it in strides); now you can actually reserve space for actual matrices up-front - but m and n now have to be compile-time constants.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Thanks a lot. This is very helpful. I very much like the idea of using `std::array` as the matrix type. – synaptik May 08 '12 at 14:41
0

A better approach would be to provide a class interface and use a single linear block of memory for the whole matrix. Then you can implement that interface in different ways, that range from an internal array of the appropriate sizes (if the sizes are part of the size), or a single std::vector<int> by providing indexing (pos = row*cols + col).

In the std::vector< std::vector<int> > approach the outer vector will allocate memory to store the inner vectors, and each one of those will allocate memory to hold its own elements. Using raw pointers, it is similar in memory layout to:

int **array = new int*[ N ];
for ( int i = 0; i < N; ++i ) 
   array[i] = new int[ M ];

That is:

[ 0 ] -------> [ 0, 1, 2, ... ]
[---]
[ 1 ] -------> [ 0, 1, 2, ... ]
[ . ]
[ . ]

Or basically N+1 separate blocks of memory.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489