4

Is there any library provide a multidimensional container to use like vector<>?

I would like to see something like:

TwoD<object_class_name> D2;
ThreeD<object_class_name> D3;

and the object_class_name could be any object instead of only the builtin types.

so I can use the object like

D2[i][j]
D3[i,j,k] or D3(i,j,k)

or similar

Thanks.

northfly
  • 113
  • 3
  • 11

5 Answers5

9

If c++11, a possible solution is using which allows aliasing of a template:

template <typename T>
using TwoD = std::vector<std::vector<T>>;

template <typename T>
using ThreeD = std::vector<std::vector<std::vector<T>>>;

usage:

TwoD<int> t2ints;
TwoD<std::string> t2strings;

ThreeD<int> t3ints;
ThreeD<std::string> t3strings;
hmjd
  • 120,187
  • 20
  • 207
  • 252
  • Thanks, Could you give more information on how to use it if defined like that? – northfly May 31 '13 at 16:08
  • @northfly, just exactly as you would use `std::vector>` or `std::vector>`. – hmjd May 31 '13 at 16:09
  • As mentioned below, doing this with std::vector is going to result in a lot of non-contiguous memory allocations. However, doing it with std::array instead will give you a single contiguous allocation. If really you do need dynamic extents, see the boost::multi_array solution below. – goertzenator Sep 04 '14 at 14:55
  • @northfly - for instance, you can initialize it to a default value like this `TwoD vec(5, std::vector(10, 1)); ` - 5 vectors holding vectors on 10 `int's` with the value 1. – joepol Feb 16 '20 at 13:48
9

boost::multi_array can do that.

2D array example:

boost::multi_array<float, 2> float2D(boost::extents[5][10]);
float2D[0][0] = 1.0f;

3D array example:

boost::multi_array<float, 3> float3D(boost::extents[5][10][20]);
float2D[0][0][0] = 1.0f;

The stored type can be a class or struct as well as a primitive type, and the memory used will be contiguous.

rhashimoto
  • 15,650
  • 2
  • 52
  • 80
2

YOu could do something like this:

std::vector<std::vector<someType> > TwoDVector;

Or a two dimensional array like these:

someType** TwoDArrayPointer;
someType TwoDArray[size][size2];
MobA11y
  • 18,425
  • 3
  • 49
  • 76
2

I don't like vector<vector> because each row gets its own separately allocated memory block on the heap. This causes two problems:

  • Iterating over all elements of the array will have very poor cache performance compared to a contiguous 2D array.
  • You can't pass the array into a function that wants a 1D array. For example, a lot of imaging libraries only want a char * for image data.

Therefore, I would suggest writing your own 2D array template. It's a pretty simple task. Or you can use my public domain code at github.com/jpreiss/array2d .

Also note: you can't overload operator[] with a function that takes more than one parameter. You can overload operator() for 2D indexing.

japreiss
  • 11,111
  • 2
  • 40
  • 77
  • do you mean, each sub-vector is not consequently stored in the memory? How could that happen, cause we know vector allow elements stored together, and vector's vector should also let all of them stored together, right? – northfly May 31 '13 at 16:31
  • 1
    `std::vector` is basically just a pointer to some heap memory, with a size value and capacity value. That's the only way `push_back` can work - it needs to reallocate a bigger chunk when the vector expands. So a `vector` is a contiguous block of **pointers** - but the real data is scattered all around the heap. – japreiss May 31 '13 at 19:39
  • 1
    ... Of course, none of this matters unless you use the 2D array in performance critical code. – japreiss May 31 '13 at 19:40
1

You can use vector.

// Create
vector< vector<int> > vec(4, vector<int>(4));
// Write
vec[2][3] = 10;
// Read
int a = vec[2][3];
Ashot
  • 10,807
  • 14
  • 66
  • 117