Kenneth Bastian
Kenneth Bastian

Reputation: 883

Initializer list on two dimensional std::array

Why does a two-dimensional array of int initialize contiguously? Meanwhile the two dimensional vector is initialize per set of numbers.

int main()
{
  array<array<int, 2>, 2> td{ 2, 6, 4, 8 }; //array of arrays
  for (int i = 0; i < 2; ++i)
    for(int j = 0; j < 2; ++j)
      cout << td[i][j] << ' ';

  cout << endl;

  vector<vector<int>> vtd{ { 5, 1 }, { 0, 2 } };  //vector of vectors
  for (int i = 0; i < 2; ++i)
    for (int j = 0; j < 2; ++j)
      cout << vtd[i][j] << ' ';

  return 0;
}

Here are the results:

2 6 4 8
5 1 0 2

Upvotes: 3

Views: 1198

Answers (4)

kfsone
kfsone

Reputation: 24269

std::vector is an object encapsulating a set of internal state: { T* data, size_t count, size_t capacity }. The actual contents of a vector are stored off in memory somewhere else.

By contrast, std::array is an encapsulation layer around a C-style array. It does not have internal state, but sits directly over a C-array.

std::vector<int> v;
v.reserve(4);
std::array<int, 4> a;

After this, what you have on the stack is as follows:

[ int* v.data ]
[ size_t v.count = 0 ]
[ size_t v.size = 4 ]
[ int[4] ]

As a result, your 2-tier std::vector is actually a vector of objects,

[ std::vector<int>* v.data --> points to second tier object in heap memory ]
[ size_t v.count ]
[ size_t v.size ]

whereas the std::array is actually just a cover for int a[2][2], which initializes exactly the way you would expect.

Upvotes: 1

Zac Howland
Zac Howland

Reputation: 15870

std::array is a very thin wrapper around a static array. It is allocated at compile time, with a known size, and each element is guaranteed to be contiguous, so when you have an array of arrays, they will all be contiguous.

Example:

std::array<T, 4> a;
|   a[0]   |   a[1]   |   a[2]   |   a[3]   |

std::array<std::array<T, 2>, 2> b;
|   a[0][0]   |   a[0][1]   |   a[1][0]   |   a[1][1]   |

Since the first array (a[0]) is guaranteed to be contiguous (as is the second array), and the parent wrapper array is also guaranteed to be contiguous, the entire structure will be contiguous.

For a vector, it is determined at runtime. The dynamic array of a vector is guaranteed to be contiguous, if it is a vector of vectors, each element in the parent vector has a pointer to a separate block of contiguous memory (each "child" vector has a size, capacity, and pointer to a block of contiguous memory).

The analogy follows:

T t[...][...] ====> std::array<std::array<T, ...>, ...>
T** t         ====> std::vector<std::vector<T>>

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409404

The difference between an array of arrays and a vector of vectors is the same as a normal array of arrays versus a pointer to pointer.

The std::array class is quite close to normal arrays (which has to be contiguous), while std::vector is closes to a pointer.

Upvotes: 1

Brian Bi
Brian Bi

Reputation: 119457

std::array is an aggregate. When an aggregate is initialized with a braced-init-list like this, each subaggregate, in order, takes as many elements from the list as it requires, and the remainder of the list is used to initialize the next element, and so on. In particular, this means that the first array in td takes the first two initializers (since it has two elements) and the second array takes the remaining two.

std::vector is not an aggregate, and has an explicitly defined constructor that takes std::initializer_list as an argument, which determines the semantics of list-initialization.

Upvotes: 3

Related Questions